From 2281f38f625cc083839f1c30a83f10f7cc4174c1 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 11 May 2016 13:13:19 +0800 Subject: [PATCH 01/83] Add 24 day code --- 24_day/!cons_9x.bat | 1 + 24_day/!cons_nt.bat | 1 + 24_day/Makefile | 212 ++ 24_day/a.c | 8 + 24_day/a_nask.nas | 188 ++ 24_day/asmhead.nas | 202 ++ 24_day/bootpack.c | 290 +++ 24_day/bootpack.h | 267 +++ 24_day/bug2.c | 3 + 24_day/bug3.c | 9 + 24_day/console.c | 494 +++++ 24_day/dsctbl.c | 60 + 24_day/fifo.c | 63 + 24_day/file.c | 74 + 24_day/graphic.c | 157 ++ 24_day/hankaku.txt | 4609 +++++++++++++++++++++++++++++++++++++++++++ 24_day/hello.nas | 16 + 24_day/hello2.nas | 9 + 24_day/hello3.c | 12 + 24_day/hello4.c | 8 + 24_day/hello5.nas | 20 + 24_day/int.c | 37 + 24_day/ipl10.nas | 109 + 24_day/keyboard.c | 44 + 24_day/lines.c | 29 + 24_day/make.bat | 1 + 24_day/memory.c | 162 ++ 24_day/mouse.c | 76 + 24_day/mtask.c | 201 ++ 24_day/naskfunc.nas | 307 +++ 24_day/sheet.c | 217 ++ 24_day/star1.c | 18 + 24_day/stars.c | 24 + 24_day/stars2.c | 26 + 24_day/timer.c | 118 ++ 24_day/walk.c | 35 + 24_day/window.c | 88 + 24_day/winhelo.c | 11 + 24_day/winhelo2.c | 15 + 24_day/winhelo3.c | 19 + 40 files changed, 8240 insertions(+) create mode 100644 24_day/!cons_9x.bat create mode 100644 24_day/!cons_nt.bat create mode 100644 24_day/Makefile create mode 100644 24_day/a.c create mode 100644 24_day/a_nask.nas create mode 100644 24_day/asmhead.nas create mode 100644 24_day/bootpack.c create mode 100644 24_day/bootpack.h create mode 100644 24_day/bug2.c create mode 100644 24_day/bug3.c create mode 100644 24_day/console.c create mode 100644 24_day/dsctbl.c create mode 100644 24_day/fifo.c create mode 100644 24_day/file.c create mode 100644 24_day/graphic.c create mode 100644 24_day/hankaku.txt create mode 100644 24_day/hello.nas create mode 100644 24_day/hello2.nas create mode 100644 24_day/hello3.c create mode 100644 24_day/hello4.c create mode 100644 24_day/hello5.nas create mode 100644 24_day/int.c create mode 100644 24_day/ipl10.nas create mode 100644 24_day/keyboard.c create mode 100644 24_day/lines.c create mode 100644 24_day/make.bat create mode 100644 24_day/memory.c create mode 100644 24_day/mouse.c create mode 100644 24_day/mtask.c create mode 100644 24_day/naskfunc.nas create mode 100644 24_day/sheet.c create mode 100644 24_day/star1.c create mode 100644 24_day/stars.c create mode 100644 24_day/stars2.c create mode 100644 24_day/timer.c create mode 100644 24_day/walk.c create mode 100644 24_day/window.c create mode 100644 24_day/winhelo.c create mode 100644 24_day/winhelo2.c create mode 100644 24_day/winhelo3.c diff --git a/24_day/!cons_9x.bat b/24_day/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/24_day/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/24_day/!cons_nt.bat b/24_day/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/24_day/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/24_day/Makefile b/24_day/Makefile new file mode 100644 index 0000000..b61f4a2 --- /dev/null +++ b/24_day/Makefile @@ -0,0 +1,212 @@ +OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \ + int.obj fifo.obj keyboard.obj mouse.obj memory.obj sheet.obj timer.obj \ + mtask.obj window.obj console.obj file.obj + +TOOLPATH = ../z_tools/ +INCPATH = ../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = $(TOOLPATH)haribote/haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +COPY = copy +DEL = del + +# 默认动作 + +default : + $(MAKE) img + +# 镜像文件生成 + +ipl10.bin : ipl10.nas Makefile + $(NASK) ipl10.nas ipl10.bin ipl10.lst + +asmhead.bin : asmhead.nas Makefile + $(NASK) asmhead.nas asmhead.bin asmhead.lst + +hankaku.bin : hankaku.txt Makefile + $(MAKEFONT) hankaku.txt hankaku.bin + +hankaku.obj : hankaku.bin Makefile + $(BIN2OBJ) hankaku.bin hankaku.obj _hankaku + +bootpack.bim : $(OBJS_BOOTPACK) Makefile + $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \ + $(OBJS_BOOTPACK) +# 3MB+64KB=3136KB + +bootpack.hrb : bootpack.bim Makefile + $(BIM2HRB) bootpack.bim bootpack.hrb 0 + +haribote.sys : asmhead.bin bootpack.hrb Makefile + copy /B asmhead.bin+bootpack.hrb haribote.sys + +hello.hrb : hello.nas Makefile + $(NASK) hello.nas hello.hrb hello.lst + +hello2.hrb : hello2.nas Makefile + $(NASK) hello2.nas hello2.hrb hello2.lst + +a.bim : a.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:a.bim map:a.map a.obj a_nask.obj + +a.hrb : a.bim Makefile + $(BIM2HRB) a.bim a.hrb 0 + +hello3.bim : hello3.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello3.bim map:hello3.map hello3.obj a_nask.obj + +hello3.hrb : hello3.bim Makefile + $(BIM2HRB) hello3.bim hello3.hrb 0 + +hello4.bim : hello4.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello4.bim stack:1k map:hello4.map \ + hello4.obj a_nask.obj + +hello4.hrb : hello4.bim Makefile + $(BIM2HRB) hello4.bim hello4.hrb 0 + +hello5.bim : hello5.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello5.bim stack:1k map:hello5.map hello5.obj + +hello5.hrb : hello5.bim Makefile + $(BIM2HRB) hello5.bim hello5.hrb 0 + +bug2.bim : bug2.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:bug2.bim map:bug2.map bug2.obj + +bug2.hrb : bug2.bim Makefile + $(BIM2HRB) bug2.bim bug2.hrb 0 + +bug3.bim : bug3.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:bug3.bim map:bug3.map bug3.obj a_nask.obj + +bug3.hrb : bug3.bim Makefile + $(BIM2HRB) bug3.bim bug3.hrb 0 + +winhelo.bim : winhelo.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:winhelo.bim stack:1k map:winhelo.map \ + winhelo.obj a_nask.obj + +winhelo.hrb : winhelo.bim Makefile + $(BIM2HRB) winhelo.bim winhelo.hrb 0 + +winhelo2.bim : winhelo2.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:winhelo2.bim stack:1k map:winhelo2.map \ + winhelo2.obj a_nask.obj + +winhelo2.hrb : winhelo2.bim Makefile + $(BIM2HRB) winhelo2.bim winhelo2.hrb 0 + +winhelo3.bim : winhelo3.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:winhelo3.bim stack:1k map:winhelo3.map \ + winhelo3.obj a_nask.obj + +winhelo3.hrb : winhelo3.bim Makefile + $(BIM2HRB) winhelo3.bim winhelo3.hrb 40k + +star1.bim : star1.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:star1.bim stack:1k map:star1.map \ + star1.obj a_nask.obj + +star1.hrb : star1.bim Makefile + $(BIM2HRB) star1.bim star1.hrb 47k + +stars.bim : stars.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:stars.bim stack:1k map:stars.map \ + stars.obj a_nask.obj + +stars.hrb : stars.bim Makefile + $(BIM2HRB) stars.bim stars.hrb 47k + +stars2.bim : stars2.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:stars2.bim stack:1k map:stars2.map \ + stars2.obj a_nask.obj + +stars2.hrb : stars2.bim Makefile + $(BIM2HRB) stars2.bim stars2.hrb 47k + +lines.bim : lines.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:lines.bim stack:1k map:lines.map \ + lines.obj a_nask.obj + +lines.hrb : lines.bim Makefile + $(BIM2HRB) lines.bim lines.hrb 48k + +walk.bim : walk.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:walk.bim stack:1k map:walk.map \ + walk.obj a_nask.obj + +walk.hrb : walk.bim Makefile + $(BIM2HRB) walk.bim walk.hrb 48k + +haribote.img : ipl10.bin haribote.sys Makefile \ + hello.hrb hello2.hrb a.hrb hello3.hrb hello4.hrb hello5.hrb \ + winhelo.hrb winhelo2.hrb winhelo3.hrb star1.hrb stars.hrb stars2.hrb \ + lines.hrb walk.hrb + $(EDIMG) imgin:../z_tools/fdimg0at.tek \ + wbinimg src:ipl10.bin len:512 from:0 to:0 \ + copy from:haribote.sys to:@: \ + copy from:ipl10.nas to:@: \ + copy from:make.bat to:@: \ + copy from:hello.hrb to:@: \ + copy from:hello2.hrb to:@: \ + copy from:a.hrb to:@: \ + copy from:hello3.hrb to:@: \ + copy from:hello4.hrb to:@: \ + copy from:hello5.hrb to:@: \ + copy from:winhelo.hrb to:@: \ + copy from:winhelo2.hrb to:@: \ + copy from:winhelo3.hrb to:@: \ + copy from:star1.hrb to:@: \ + copy from:stars.hrb to:@: \ + copy from:stars2.hrb to:@: \ + copy from:lines.hrb to:@: \ + copy from:walk.hrb to:@: \ + imgout:haribote.img + +# 其他指令 + +%.gas : %.c bootpack.h Makefile + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +# 运行程序 + +img : + $(MAKE) haribote.img + +run : + $(MAKE) img + $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../z_tools/qemu + +install : + $(MAKE) img + $(IMGTOL) w a: haribote.img + +clean : + -$(DEL) *.bin + -$(DEL) *.lst + -$(DEL) *.obj + -$(DEL) bootpack.map + -$(DEL) bootpack.bim + -$(DEL) bootpack.hrb + -$(DEL) haribote.sys + +src_only : + $(MAKE) clean + -$(DEL) haribote.img diff --git a/24_day/a.c b/24_day/a.c new file mode 100644 index 0000000..a6668af --- /dev/null +++ b/24_day/a.c @@ -0,0 +1,8 @@ +void api_putchar(int c); +void api_end(void); + +void HariMain(void) +{ + api_putchar('A'); + api_end(); +} diff --git a/24_day/a_nask.nas b/24_day/a_nask.nas new file mode 100644 index 0000000..bce3b4a --- /dev/null +++ b/24_day/a_nask.nas @@ -0,0 +1,188 @@ +[FORMAT "WCOFF"] ; 生成对象文件的模式 +[INSTRSET "i486p"] ; 表示使用486兼容指令集 +[BITS 32] ; 生成32位模式机器语言 +[FILE "a_nask.nas"] ; 源文件名信息 + + GLOBAL _api_putchar + GLOBAL _api_putstr0 + GLOBAL _api_end + GLOBAL _api_openwin + GLOBAL _api_putstrwin + GLOBAL _api_boxfilwin + GLOBAL _api_initmalloc + GLOBAL _api_malloc + GLOBAL _api_free + GLOBAL _api_point + GLOBAL _api_refreshwin + GLOBAL _api_linewin + GLOBAL _api_closewin + GLOBAL _api_getkey + +[SECTION .text] + +_api_putchar: ; void api_putchar(int c); + MOV EDX,1 + MOV AL,[ESP+4] ; c + INT 0x40 + RET + +_api_putstr0: ; void api_putstr0(char *s); + PUSH EBX + MOV EDX,2 + MOV EBX,[ESP+8] ; s + INT 0x40 + POP EBX + RET + +_api_end: ; void api_end(void); + MOV EDX,4 + INT 0x40 + +_api_openwin: ; int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,5 + MOV EBX,[ESP+16] ; buf + MOV ESI,[ESP+20] ; xsiz + MOV EDI,[ESP+24] ; ysiz + MOV EAX,[ESP+28] ; col_inv + MOV ECX,[ESP+32] ; title + INT 0x40 + POP EBX + POP ESI + POP EDI + RET + +_api_putstrwin: ; void api_putstrwin(int win, int x, int y, int col, int len, char *str); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,6 + MOV EBX,[ESP+20] ; win + MOV ESI,[ESP+24] ; x + MOV EDI,[ESP+28] ; y + MOV EAX,[ESP+32] ; col + MOV ECX,[ESP+36] ; len + MOV EBP,[ESP+40] ; str + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET + +_api_boxfilwin: ; void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,7 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET + +_api_initmalloc: ; void api_initmalloc(void); + PUSH EBX + MOV EDX,8 + MOV EBX,[CS:0x0020] ; malloc内存空间的地址 + MOV EAX,EBX + ADD EAX,32*1024 ; 加上32KB + MOV ECX,[CS:0x0000] ; 数据段的大小 + SUB ECX,EAX + INT 0x40 + POP EBX + RET + +_api_malloc: ; char *api_malloc(int size); + PUSH EBX + MOV EDX,9 + MOV EBX,[CS:0x0020] + MOV ECX,[ESP+8] ; size + INT 0x40 + POP EBX + RET + +_api_free: ; void api_free(char *addr, int size); + PUSH EBX + MOV EDX,10 + MOV EBX,[CS:0x0020] + MOV EAX,[ESP+ 8] ; addr + MOV ECX,[ESP+12] ; size + INT 0x40 + POP EBX + RET + +_api_point: ; void api_point(int win, int x, int y, int col); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,11 + MOV EBX,[ESP+16] ; win + MOV ESI,[ESP+20] ; x + MOV EDI,[ESP+24] ; y + MOV EAX,[ESP+28] ; col + INT 0x40 + POP EBX + POP ESI + POP EDI + RET + +_api_refreshwin: ; void api_refreshwin(int win, int x0, int y0, int x1, int y1); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,12 + MOV EBX,[ESP+16] ; win + MOV EAX,[ESP+20] ; x0 + MOV ECX,[ESP+24] ; y0 + MOV ESI,[ESP+28] ; x1 + MOV EDI,[ESP+32] ; y1 + INT 0x40 + POP EBX + POP ESI + POP EDI + RET + +_api_linewin: ; void api_linewin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,13 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET + +_api_closewin: ; void api_closewin(int win); + PUSH EBX + MOV EDX,14 + MOV EBX,[ESP+8] ; win + INT 0x40 + POP EBX + RET + +_api_getkey: ; int api_getkey(int mode); + MOV EDX,15 + MOV EAX,[ESP+4] ; mode + INT 0x40 + RET diff --git a/24_day/asmhead.nas b/24_day/asmhead.nas new file mode 100644 index 0000000..ad35d76 --- /dev/null +++ b/24_day/asmhead.nas @@ -0,0 +1,202 @@ +; haribote-os boot asm +; TAB=4 + +[INSTRSET "i486p"] + +VBEMODE EQU 0x105 ; 1024 x 768 x 8bit 彩色 +; 显示模式 +; 0x100 : 640 x 400 x 8bit 彩色 +; 0x101 : 640 x 480 x 8bit 彩色 +; 0x103 : 800 x 600 x 8bit 彩色 +; 0x105 : 1024 x 768 x 8bit 彩色 +; 0x107 : 1280 x 1024 x 8bit 彩色 + +BOTPAK EQU 0x00280000 ; 加载bootpack +DSKCAC EQU 0x00100000 ; 磁盘缓存的位置 +DSKCAC0 EQU 0x00008000 ; 磁盘缓存的位置(实模式) + +; BOOT_INFO 相关 +CYLS EQU 0x0ff0 ; 引导扇区设置 +LEDS EQU 0x0ff1 +VMODE EQU 0x0ff2 ; 关于颜色的信息 +SCRNX EQU 0x0ff4 ; 分辨率X +SCRNY EQU 0x0ff6 ; 分辨率Y +VRAM EQU 0x0ff8 ; 图像缓冲区的起始地址 + + ORG 0xc200 ; 这个的程序要被装载的内存地址 + +; 确认VBE是否存在 + + MOV AX,0x9000 + MOV ES,AX + MOV DI,0 + MOV AX,0x4f00 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 检查VBE的版本 + + MOV AX,[ES:DI+4] + CMP AX,0x0200 + JB scrn320 ; if (AX < 0x0200) goto scrn320 + +; 取得画面模式信息 + + MOV CX,VBEMODE + MOV AX,0x4f01 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 画面模式信息的确认 + CMP BYTE [ES:DI+0x19],8 ;颜色数必须为8 + JNE scrn320 + CMP BYTE [ES:DI+0x1b],4 ;颜色的指定方法必须为4(4是调色板模式) + JNE scrn320 + MOV AX,[ES:DI+0x00] ;模式属性bit7不是1就不能加上0x4000 + AND AX,0x0080 + JZ scrn320 ; 模式属性的bit7是0,所以放弃 + +; 画面设置 + + MOV BX,VBEMODE+0x4000 + MOV AX,0x4f02 + INT 0x10 + MOV BYTE [VMODE],8 ; 屏幕的模式(参考C语言的引用) + MOV AX,[ES:DI+0x12] + MOV [SCRNX],AX + MOV AX,[ES:DI+0x14] + MOV [SCRNY],AX + MOV EAX,[ES:DI+0x28] ;VRAM的地址 + MOV [VRAM],EAX + JMP keystatus + +scrn320: + MOV AL,0x13 ; VGA图、320x200x8bit彩色 + MOV AH,0x00 + INT 0x10 + MOV BYTE [VMODE],8 ; 记下画面模式(参考C语言) + MOV WORD [SCRNX],320 + MOV WORD [SCRNY],200 + MOV DWORD [VRAM],0x000a0000 + +; 通过 BIOS 获取指示灯状态 + +keystatus: + MOV AH,0x02 + INT 0x16 ; keyboard BIOS + MOV [LEDS],AL + +; PIC关闭一切中断 +; 根据AT兼容机的规格,如果要初始化PIC, +; 必须在CLI之前进行,否则有时会挂起。 +; 随后进行PIC的初始化。 + + MOV AL,0xff + OUT 0x21,AL + NOP ; 如果连续执行OUT指令,有些机种会无法正常运行 + OUT 0xa1,AL + + CLI ; 禁止CPU级别的中断 + +; 为了让CPU能够访问1MB以上的内存空间,设定A20GATE + + CALL waitkbdout + MOV AL,0xd1 + OUT 0x64,AL + CALL waitkbdout + MOV AL,0xdf ; enable A20 + OUT 0x60,AL + CALL waitkbdout + +; 切换到保护模式 + +[INSTRSET "i486p"] ; 说明使用486指令 + + LGDT [GDTR0] ; 设置临时GDT + MOV EAX,CR0 + AND EAX,0x7fffffff ; 设bit31为0(禁用分页) + OR EAX,0x00000001 ; bit0到1转换(保护模式过渡) + MOV CR0,EAX + JMP pipelineflush +pipelineflush: + MOV AX,1*8 ; 可读写的段 32bit + MOV DS,AX + MOV ES,AX + MOV FS,AX + MOV GS,AX + MOV SS,AX + +; bootpack传递 + + MOV ESI,bootpack ; 转送源 + MOV EDI,BOTPAK ; 转送目标 + MOV ECX,512*1024/4 + CALL memcpy + +; 磁盘数据最终转送到它本来的位置去 +; 首先从启动扇区开始 + + MOV ESI,0x7c00 ; 转送源 + MOV EDI,DSKCAC ; 转送目标 + MOV ECX,512/4 + CALL memcpy + +; 剩余的全部 + + MOV ESI,DSKCAC0+512 ; 转送源 + MOV EDI,DSKCAC+512 ; 转送源目标 + MOV ECX,0 + MOV CL,BYTE [CYLS] + IMUL ECX,512*18*2/4 ; 从柱面数变换为字节数/4 + SUB ECX,512/4 ; 减去 IPL 偏移量 + CALL memcpy + +; 必须由asmhead来完成的工作,至此全部完毕 +; 以后就交由bootpack来完成 + +; bootpack启动 + + MOV EBX,BOTPAK + MOV ECX,[EBX+16] + ADD ECX,3 ; ECX += 3; + SHR ECX,2 ; ECX /= 4; + JZ skip ; 没有要转送的东西时 + MOV ESI,[EBX+20] ; 转送源 + ADD ESI,EBX + MOV EDI,[EBX+12] ; 转送目标 + CALL memcpy +skip: + MOV ESP,[EBX+12] ; 堆栈的初始化 + JMP DWORD 2*8:0x0000001b + +waitkbdout: + IN AL,0x64 + AND AL,0x02 + JNZ waitkbdout ; AND的结果如果不是0,就跳到waitkbdout + RET + +memcpy: + MOV EAX,[ESI] + ADD ESI,4 + MOV [EDI],EAX + ADD EDI,4 + SUB ECX,1 + JNZ memcpy ; 减法运算的结果如果不是0,就跳转到memcpy + RET +; memcpy地址前缀大小 + + ALIGNB 16 +GDT0: + RESB 8 ; 初始值 + DW 0xffff,0x0000,0x9200,0x00cf ; 可以读写的段(segment)32bit + DW 0xffff,0x0000,0x9a28,0x0047 ; 可执行的文件的32bit寄存器(bootpack用) + + DW 0 +GDTR0: + DW 8*3-1 + DD GDT0 + + ALIGNB 16 +bootpack: diff --git a/24_day/bootpack.c b/24_day/bootpack.c new file mode 100644 index 0000000..c0c9240 --- /dev/null +++ b/24_day/bootpack.c @@ -0,0 +1,290 @@ +/* bootpack */ + +#include "bootpack.h" +#include + +#define KEYCMD_LED 0xed + +void HariMain(void) +{ + struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; + struct SHTCTL *shtctl; + char s[40]; + struct FIFO32 fifo, keycmd; + int fifobuf[128], keycmd_buf[32]; + int mx, my, i, cursor_x, cursor_c; + unsigned int memtotal; + struct MOUSE_DEC mdec; + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + unsigned char *buf_back, buf_mouse[256], *buf_win, *buf_cons; + struct SHEET *sht_back, *sht_mouse, *sht_win, *sht_cons; + struct TASK *task_a, *task_cons; + struct TIMER *timer; + static char keytable0[0x80] = { + 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0 + }; + static char keytable1[0x80] = { + 0, 0, '!', 0x22, '#', '$', '%', '&', 0x27, '(', ')', '~', '=', '~', 0, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', '+', '*', 0, 0, '}', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, '|', 0, 0 + }; + int key_to = 0, key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; + struct CONSOLE *cons; + + init_gdtidt(); + init_pic(); + io_sti(); /* IDT/PIC的初始化已经完成,于是开放CPU的中断 */ + fifo32_init(&fifo, 128, fifobuf, 0); + init_pit(); + init_keyboard(&fifo, 256); + enable_mouse(&fifo, 512, &mdec); + io_out8(PIC0_IMR, 0xf8); /* 设定PIT和PIC1以及键盘为许可(11111000) */ + io_out8(PIC1_IMR, 0xef); /* 开放鼠标中断(11101111) */ + fifo32_init(&keycmd, 32, keycmd_buf, 0); + + memtotal = memtest(0x00400000, 0xbfffffff); + memman_init(memman); + memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */ + memman_free(memman, 0x00400000, memtotal - 0x00400000); + + init_palette(); + shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny); + task_a = task_init(memman); + fifo.task = task_a; + task_run(task_a, 1, 2); + *((int *) 0x0fe4) = (int) shtctl; + + /* sht_back */ + sht_back = sheet_alloc(shtctl); + buf_back = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny); + sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 无透明色 */ + init_screen8(buf_back, binfo->scrnx, binfo->scrny); + + /* sht_cons */ + sht_cons = sheet_alloc(shtctl); + buf_cons = (unsigned char *) memman_alloc_4k(memman, 256 * 165); + sheet_setbuf(sht_cons, buf_cons, 256, 165, -1); /* 无透明色 */ + make_window8(buf_cons, 256, 165, "console", 0); + make_textbox8(sht_cons, 8, 28, 240, 128, COL8_000000); + task_cons = task_alloc(); + task_cons->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 12; + task_cons->tss.eip = (int) &console_task; + task_cons->tss.es = 1 * 8; + task_cons->tss.cs = 2 * 8; + task_cons->tss.ss = 1 * 8; + task_cons->tss.ds = 1 * 8; + task_cons->tss.fs = 1 * 8; + task_cons->tss.gs = 1 * 8; + *((int *) (task_cons->tss.esp + 4)) = (int) sht_cons; + *((int *) (task_cons->tss.esp + 8)) = memtotal; + task_run(task_cons, 2, 2); /* level=2, priority=2 */ + + /* sht_win */ + sht_win = sheet_alloc(shtctl); + buf_win = (unsigned char *) memman_alloc_4k(memman, 160 * 52); + sheet_setbuf(sht_win, buf_win, 144, 52, -1); /* 无透明色 */ + make_window8(buf_win, 144, 52, "task_a", 1); + make_textbox8(sht_win, 8, 28, 128, 16, COL8_FFFFFF); + cursor_x = 8; + cursor_c = COL8_FFFFFF; + timer = timer_alloc(); + timer_init(timer, &fifo, 1); + timer_settime(timer, 50); + + /* sht_mouse */ + sht_mouse = sheet_alloc(shtctl); + sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99); + init_mouse_cursor8(buf_mouse, 99); + mx = (binfo->scrnx - 16) / 2; /* 计算坐标使其位于画面中央 */ + my = (binfo->scrny - 28 - 16) / 2; + + sheet_slide(sht_back, 0, 0); + sheet_slide(sht_cons, 32, 4); + sheet_slide(sht_win, 64, 56); + sheet_slide(sht_mouse, mx, my); + sheet_updown(sht_back, 0); + sheet_updown(sht_cons, 1); + sheet_updown(sht_win, 2); + sheet_updown(sht_mouse, 3); + + /*为了避免和键盘当前状态冲突,在一开始先进行设置*/ + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + + for (;;) { + if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0) { + /*如果存在向键盘控制器发送的数据,则发送它 */ + keycmd_wait = fifo32_get(&keycmd); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + io_cli(); + if (fifo32_status(&fifo) == 0) { + task_sleep(task_a); + io_sti(); + } else { + i = fifo32_get(&fifo); + io_sti(); + if (256 <= i && i <= 511) { /* 键盘数据*/ + if (i < 0x80 + 256) { /*将按键编码转换为字符编码*/ + if (key_shift == 0) { + s[0] = keytable0[i - 256]; + } else { + s[0] = keytable1[i - 256]; + } + } else { + s[0] = 0; + } + if ('A' <= s[0] && s[0] <= 'Z') { /*当输入字符为英文字母时*/ + if (((key_leds & 4) == 0 && key_shift == 0) ||((key_leds & 4) != 0 && key_shift != 0)) { + s[0] += 0x20; /*将大写字母转换为小写字母*/ + } + } + if (s[0] != 0) { /*一般字符*/ + if (key_to == 0) { /*发送给任务A */ + if (cursor_x < 128) { + /*显示一个字符之后将光标后移一位*/ + s[1] = 0; + putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1); + cursor_x += 8; + } + } else { /*发送给命令行窗口*/ + fifo32_put(&task_cons->fifo, s[0] + 256); + } + } + if (i == 256 + 0x0e) { /* 退格键 */ + if (key_to == 0) { /*发送给任务A */ + if (cursor_x > 8) { + /*用空白擦除光标后将光标前移一位*/ + putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1); + cursor_x -= 8; + } + } else { /*发送给命令行窗口*/ + fifo32_put(&task_cons->fifo, 8 + 256); + } + } + if (i == 256 + 0x1c) { /*回车键*/ + if (key_to != 0) { /*发送至命令行窗口*/ + fifo32_put(&task_cons->fifo, 10 + 256); + } + } + if (i == 256 + 0x0f) { /* Tab */ + if (key_to == 0) { + key_to = 1; + make_wtitle8(buf_win, sht_win->bxsize, "task_a", 0); + make_wtitle8(buf_cons, sht_cons->bxsize, "console", 1); + cursor_c = -1; /* 不显示光标 */ + boxfill8(sht_win->buf, sht_win->bxsize, COL8_FFFFFF, cursor_x, 28, cursor_x + 7, 43); + fifo32_put(&task_cons->fifo, 2); /*命令行窗口光标ON */ + } else { + key_to = 0; + make_wtitle8(buf_win, sht_win->bxsize, "task_a", 1); + make_wtitle8(buf_cons, sht_cons->bxsize, "console", 0); + cursor_c = COL8_000000; + fifo32_put(&task_cons->fifo, 3); /*命令行窗口光标OFF */ + } + sheet_refresh(sht_win, 0, 0, sht_win->bxsize, 21); + sheet_refresh(sht_cons, 0, 0, sht_cons->bxsize, 21); + } + if (i == 256 + 0x2a) { /*左Shift ON */ + key_shift |= 1; + } + if (i == 256 + 0x36) { /*右Shift ON */ + key_shift |= 2; + } + if (i == 256 + 0xaa) { /*左Shift OFF */ + key_shift &= ~1; + } + if (i == 256 + 0xb6) { /*右Shift OFF */ + key_shift &= ~2; + } + if (i == 256 + 0x3a) { /* CapsLock */ + key_leds ^= 4; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x45) { /* NumLock */ + key_leds ^= 2; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x46) { /* ScrollLock */ + key_leds ^= 1; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x3b && key_shift != 0 && task_cons->tss.ss0 != 0) { /* Shift+F1 */ + cons = (struct CONSOLE *) *((int *) 0x0fec); + cons_putstr0(cons, "\nBreak(key) :\n"); + io_cli(); /*不能在改变寄存器值时切换到其他任务*/ + task_cons->tss.eax = (int) &(task_cons->tss.esp0); + task_cons->tss.eip = (int) asm_end_app; + io_sti(); + } + if (i == 256 + 0xfa) { /*键盘成功接收到数据*/ + keycmd_wait = -1; + } + if (i == 256 + 0xfe) { /*键盘没有成功接收到数据*/ + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + /*重新显示光标*/ + if (cursor_c >= 0) { + boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); + } + sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44); + } else if (512 <= i && i <= 767) { /* 鼠标数据*/ + if (mouse_decode(&mdec, i - 512) != 0) { + /* 已经收集了3字节的数据,移动光标 */ + mx += mdec.x; + my += mdec.y; + if (mx < 0) { + mx = 0; + } + if (my < 0) { + my = 0; + } + if (mx > binfo->scrnx - 1) { + mx = binfo->scrnx - 1; + } + if (my > binfo->scrny - 1) { + my = binfo->scrny - 1; + } + sheet_slide(sht_mouse, mx, my);/* 包含sheet_refresh含sheet_refresh */ + if ((mdec.btn & 0x01) != 0) { /* 按下左键、移动sht_win */ + sheet_slide(sht_win, mx - 80, my - 8); + } + } + } else if (i <= 1) { /* 光标用定时器*/ + if (i != 0) { + timer_init(timer, &fifo, 0); /* 下面设定0 */ + if (cursor_c >= 0) { + cursor_c = COL8_000000; + } + } else { + timer_init(timer, &fifo, 1); /* 下面设定1 */ + if (cursor_c >= 0) { + cursor_c = COL8_FFFFFF; + } + } + timer_settime(timer, 50); + if (cursor_c >= 0) { + boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); + sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44); + } + } + } + } +} diff --git a/24_day/bootpack.h b/24_day/bootpack.h new file mode 100644 index 0000000..cea84d2 --- /dev/null +++ b/24_day/bootpack.h @@ -0,0 +1,267 @@ +/* asmhead.nas */ +struct BOOTINFO { /* 0x0ff0-0x0fff */ + char cyls; /* 启动区读磁盘读到此为止 */ + char leds; /* 启动时键盘的LED的状态 */ + char vmode; /* 显卡模式为多少位彩色 */ + char reserve; + short scrnx, scrny; /* 画面分辨率 */ + char *vram; +}; +#define ADR_BOOTINFO 0x00000ff0 +#define ADR_DISKIMG 0x00100000 + +/* naskfunc.nas */ +void io_hlt(void); +void io_cli(void); +void io_sti(void); +void io_stihlt(void); +int io_in8(int port); +void io_out8(int port, int data); +int io_load_eflags(void); +void io_store_eflags(int eflags); +void load_gdtr(int limit, int addr); +void load_idtr(int limit, int addr); +int load_cr0(void); +void store_cr0(int cr0); +void load_tr(int tr); +void asm_inthandler0c(void); +void asm_inthandler0d(void); +void asm_inthandler20(void); +void asm_inthandler21(void); +void asm_inthandler27(void); +void asm_inthandler2c(void); +unsigned int memtest_sub(unsigned int start, unsigned int end); +void farjmp(int eip, int cs); +void farcall(int eip, int cs); +void asm_hrb_api(void); +void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); +void asm_end_app(void); + +/* fifo.c */ +struct FIFO32 { + int *buf; + int p, q, size, free, flags; + struct TASK *task; +}; +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task); +int fifo32_put(struct FIFO32 *fifo, int data); +int fifo32_get(struct FIFO32 *fifo); +int fifo32_status(struct FIFO32 *fifo); + +/* graphic.c */ +void init_palette(void); +void set_palette(int start, int end, unsigned char *rgb); +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); +void init_screen8(char *vram, int x, int y); +void putfont8(char *vram, int xsize, int x, int y, char c, char *font); +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s); +void init_mouse_cursor8(char *mouse, char bc); +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize); +#define COL8_000000 0 +#define COL8_FF0000 1 +#define COL8_00FF00 2 +#define COL8_FFFF00 3 +#define COL8_0000FF 4 +#define COL8_FF00FF 5 +#define COL8_00FFFF 6 +#define COL8_FFFFFF 7 +#define COL8_C6C6C6 8 +#define COL8_840000 9 +#define COL8_008400 10 +#define COL8_848400 11 +#define COL8_000084 12 +#define COL8_840084 13 +#define COL8_008484 14 +#define COL8_848484 15 + +/* dsctbl.c */ +struct SEGMENT_DESCRIPTOR { + short limit_low, base_low; + char base_mid, access_right; + char limit_high, base_high; +}; +struct GATE_DESCRIPTOR { + short offset_low, selector; + char dw_count, access_right; + short offset_high; +}; +void init_gdtidt(void); +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar); +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar); +#define ADR_IDT 0x0026f800 +#define LIMIT_IDT 0x000007ff +#define ADR_GDT 0x00270000 +#define LIMIT_GDT 0x0000ffff +#define ADR_BOTPAK 0x00280000 +#define LIMIT_BOTPAK 0x0007ffff +#define AR_DATA32_RW 0x4092 +#define AR_CODE32_ER 0x409a +#define AR_TSS32 0x0089 +#define AR_INTGATE32 0x008e + +/* int.c */ +void init_pic(void); +void inthandler27(int *esp); +#define PIC0_ICW1 0x0020 +#define PIC0_OCW2 0x0020 +#define PIC0_IMR 0x0021 +#define PIC0_ICW2 0x0021 +#define PIC0_ICW3 0x0021 +#define PIC0_ICW4 0x0021 +#define PIC1_ICW1 0x00a0 +#define PIC1_OCW2 0x00a0 +#define PIC1_IMR 0x00a1 +#define PIC1_ICW2 0x00a1 +#define PIC1_ICW3 0x00a1 +#define PIC1_ICW4 0x00a1 + +/* keyboard.c */ +void inthandler21(int *esp); +void wait_KBC_sendready(void); +void init_keyboard(struct FIFO32 *fifo, int data0); +#define PORT_KEYDAT 0x0060 +#define PORT_KEYCMD 0x0064 + +/* mouse.c */ +struct MOUSE_DEC { + unsigned char buf[3], phase; + int x, y, btn; +}; +void inthandler2c(int *esp); +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec); +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat); + +/* memory.c */ +#define MEMMAN_FREES 4090 /* 大约是32KB*/ +#define MEMMAN_ADDR 0x003c0000 +struct FREEINFO { /* 可用信息 */ + unsigned int addr, size; +}; +struct MEMMAN { /* 内存管理 */ + int frees, maxfrees, lostsize, losts; + struct FREEINFO free[MEMMAN_FREES]; +}; +unsigned int memtest(unsigned int start, unsigned int end); +void memman_init(struct MEMMAN *man); +unsigned int memman_total(struct MEMMAN *man); +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size); +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size); +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size); +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size); + +/* sheet.c */ +#define MAX_SHEETS 256 +struct SHEET { + unsigned char *buf; + int bxsize, bysize, vx0, vy0, col_inv, height, flags; + struct SHTCTL *ctl; + struct TASK *task; +}; +struct SHTCTL { + unsigned char *vram, *map; + int xsize, ysize, top; + struct SHEET *sheets[MAX_SHEETS]; + struct SHEET sheets0[MAX_SHEETS]; +}; +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize); +struct SHEET *sheet_alloc(struct SHTCTL *ctl); +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv); +void sheet_updown(struct SHEET *sht, int height); +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1); +void sheet_slide(struct SHEET *sht, int vx0, int vy0); +void sheet_free(struct SHEET *sht); + +/* timer.c */ +#define MAX_TIMER 500 +struct TIMER { + struct TIMER *next; + unsigned int timeout, flags; + struct FIFO32 *fifo; + int data; +}; +struct TIMERCTL { + unsigned int count, next; + struct TIMER *t0; + struct TIMER timers0[MAX_TIMER]; +}; +extern struct TIMERCTL timerctl; +void init_pit(void); +struct TIMER *timer_alloc(void); +void timer_free(struct TIMER *timer); +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data); +void timer_settime(struct TIMER *timer, unsigned int timeout); +void inthandler20(int *esp); + +/* mtask.c */ +#define MAX_TASKS 1000 /*最大任务数量*/ +#define TASK_GDT0 3 /*定义从GDT的几号开始分配给TSS */ +#define MAX_TASKS_LV 100 +#define MAX_TASKLEVELS 10 +struct TSS32 { + int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3; + int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi; + int es, cs, ss, ds, fs, gs; + int ldtr, iomap; +}; +struct TASK { + int sel, flags; /* sel用来存放GDT的编号*/ + int level, priority; /* 优先级 */ + struct FIFO32 fifo; + struct TSS32 tss; +}; +struct TASKLEVEL { + int running; /*正在运行的任务数量*/ + int now; /*这个变量用来记录当前正在运行的是哪个任务*/ + struct TASK *tasks[MAX_TASKS_LV]; +}; +struct TASKCTL { + int now_lv; /*现在活动中的LEVEL */ + char lv_change; /*在下次任务切换时是否需要改变LEVEL */ + struct TASKLEVEL level[MAX_TASKLEVELS]; + struct TASK tasks0[MAX_TASKS]; +}; +extern struct TIMER *task_timer; +struct TASK *task_init(struct MEMMAN *memman); +struct TASK *task_alloc(void); +void task_run(struct TASK *task, int level, int priority); +void task_switch(void); +void task_sleep(struct TASK *task); + +/* window.c */ +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act); +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l); +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c); +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act); + +/* console.c */ +struct CONSOLE { + struct SHEET *sht; + int cur_x, cur_y, cur_c; + struct TIMER *timer; +}; +void console_task(struct SHEET *sheet, unsigned int memtotal); +void cons_putchar(struct CONSOLE *cons, int chr, char move); +void cons_newline(struct CONSOLE *cons); +void cons_putstr0(struct CONSOLE *cons, char *s); +void cons_putstr1(struct CONSOLE *cons, char *s, int l); +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, unsigned int memtotal); +void cmd_mem(struct CONSOLE *cons, unsigned int memtotal); +void cmd_cls(struct CONSOLE *cons); +void cmd_dir(struct CONSOLE *cons); +void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline); +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline); +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax); +int *inthandler0c(int *esp); +int *inthandler0d(int *esp); + +/* file.c */ +struct FILEINFO { + unsigned char name[8], ext[3], type; + char reserve[10]; + unsigned short time, date, clustno; + unsigned int size; +}; +void file_readfat(int *fat, unsigned char *img); +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img); +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max); diff --git a/24_day/bug2.c b/24_day/bug2.c new file mode 100644 index 0000000..c6f65e7 --- /dev/null +++ b/24_day/bug2.c @@ -0,0 +1,3 @@ +void HariMain(void){ + for (;;) { } +} \ No newline at end of file diff --git a/24_day/bug3.c b/24_day/bug3.c new file mode 100644 index 0000000..5982e10 --- /dev/null +++ b/24_day/bug3.c @@ -0,0 +1,9 @@ +void api_putchar(int c); +void api_end(void); + +void HariMain(void) +{ + for (;;) { + api_putchar('a'); + } +} diff --git a/24_day/console.c b/24_day/console.c new file mode 100644 index 0000000..37586b0 --- /dev/null +++ b/24_day/console.c @@ -0,0 +1,494 @@ +/* 命令行窗口相关 */ + +#include "bootpack.h" +#include +#include + +void console_task(struct SHEET *sheet, unsigned int memtotal) +{ + struct TIMER *timer; + struct TASK *task = task_now(); + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + int i, fifobuf[128], *fat = (int *) memman_alloc_4k(memman, 4 * 2880); + struct CONSOLE cons; + char cmdline[30]; + cons.sht = sheet; + cons.cur_x = 8; + cons.cur_y = 28; + cons.cur_c = -1; + *((int *) 0x0fec) = (int) &cons; + + fifo32_init(&task->fifo, 128, fifobuf, task); + timer = timer_alloc(); + timer_init(timer, &task->fifo, 1); + timer_settime(timer, 50); + file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); + + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + task_sleep(task); + io_sti(); + } else { + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1) { /*光标用定时器*/ + if (i != 0) { + timer_init(timer, &task->fifo, 0); /*下次置0 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_FFFFFF; + } + } else { + timer_init(timer, &task->fifo, 1); /*下次置1 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_000000; + } + } + timer_settime(timer, 50); + } + if (i == 2) { /*光标ON */ + cons.cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + boxfill8(sheet->buf, sheet->bxsize, COL8_000000, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + cons.cur_c = -1; + } + if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/ + if (i == 8 + 256) { + /*退格键*/ + if (cons.cur_x > 16) { + /*用空格擦除光标后将光标前移一位*/ + cons_putchar(&cons, ' ', 0); + cons.cur_x -= 8; + } + } else if (i == 10 + 256) { + /*回车键*/ + /*将光标用空格擦除后换行 */ + cons_putchar(&cons, ' ', 0); + cmdline[cons.cur_x / 8 - 2] = 0; + cons_newline(&cons); + cons_runcmd(cmdline, &cons, fat, memtotal); /*运行命令*/ + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + } else { + /*一般字符*/ + if (cons.cur_x < 240) { + /*显示一个字符之后将光标后移一位*/ + cmdline[cons.cur_x / 8 - 2] = i - 256; + cons_putchar(&cons, i - 256, 1); + } + } + } + /*重新显示光标*/ + if (cons.cur_c >= 0) { + boxfill8(sheet->buf, sheet->bxsize, cons.cur_c, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + } + sheet_refresh(sheet, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16); + } + } +} + +void cons_putchar(struct CONSOLE *cons, int chr, char move) +{ + char s[2]; + s[0] = chr; + s[1] = 0; + if (s[0] == 0x09) { /*制表符*/ + for (;;) { + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1); + cons->cur_x += 8; + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + if (((cons->cur_x - 8) & 0x1f) == 0) { + break; /*被32整除则break*/ + } + } + } else if (s[0] == 0x0a) { /*换行*/ + cons_newline(cons); + } else if (s[0] == 0x0d) { /*回车*/ + /*先不做任何操作*/ + } else { /*一般字符*/ + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1); + if (move != 0) { + /* move为0时光标不后移*/ + cons->cur_x += 8; + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + } + } + return; +} + +void cons_newline(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + if (cons->cur_y < 28 + 112) { + cons->cur_y += 16; /*到下一行*/ + } else { + /*滚动*/ + for (y = 28; y < 28 + 112; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize]; + } + } + for (y = 28 + 112; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + } + cons->cur_x = 8; + return; +} + +void cons_putstr0(struct CONSOLE *cons, char *s) +{ + for (; *s != 0; s++) { + cons_putchar(cons, *s, 1); + } + return; +} + +void cons_putstr1(struct CONSOLE *cons, char *s, int l) +{ + int i; + for (i = 0; i < l; i++) { + cons_putchar(cons, s[i], 1); + } + return; +} + +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, unsigned int memtotal) +{ + if (strcmp(cmdline, "mem") == 0) { + cmd_mem(cons, memtotal); + } else if (strcmp(cmdline, "cls") == 0) { + cmd_cls(cons); + } else if (strcmp(cmdline, "dir") == 0 || strcmp(cmdline, "ls") == 0) { + cmd_dir(cons); + } else if (strncmp(cmdline, "type ", 5) == 0) { + cmd_type(cons, fat, cmdline); + } else if (cmdline[0] != 0) { + if (cmd_app(cons, fat, cmdline) == 0) { + /*不是命令,不是应用程序,也不是空行*/ + cons_putstr0(cons, "Bad command.\n\n"); + } + } + return; +} + +void cmd_mem(struct CONSOLE *cons, unsigned int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + char s[60]; + sprintf(s, "total %dMB\nfree %dKB\n\n", memtotal / (1024 * 1024), memman_total(memman) / 1024); + cons_putstr0(cons, s); + return; +} + +void cmd_cls(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + for (y = 28; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + cons->cur_y = 28; + return; +} + +void cmd_dir(struct CONSOLE *cons) +{ + struct FILEINFO *finfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600); + int i, j; + char s[30]; + for (i = 0; i < 224; i++) { + if (finfo[i].name[0] == 0x00) { + break; + } + if (finfo[i].name[0] != 0xe5) { + if ((finfo[i].type & 0x18) == 0) { + sprintf(s, "filename.ext %7d\n", finfo[i].size); + for (j = 0; j < 8; j++) { + s[j] = finfo[i].name[j]; + } + s[ 9] = finfo[i].ext[0]; + s[10] = finfo[i].ext[1]; + s[11] = finfo[i].ext[2]; + cons_putstr0(cons, s); + } + } + } + cons_newline(cons); + return; +} + +void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct FILEINFO *finfo = file_search(cmdline + 5, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + char *p; + if (finfo != 0) { + /*找到文件的情况*/ + p = (char *) memman_alloc_4k(memman, finfo->size); + file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); + cons_putstr1(cons, p, finfo->size); + memman_free_4k(memman, (int) p, finfo->size); + } else { + /*没有找到文件的情况*/ + cons_putstr0(cons, "File not found.\n"); + } + cons_newline(cons); + return; +} + +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct FILEINFO *finfo; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + char name[18], *p, *q; + struct TASK *task = task_now(); + int i, segsiz, datsiz, esp, dathrb; + struct SHTCTL *shtctl; + struct SHEET *sht; + + /*根据命令行生成文件名*/ + for (i = 0; i < 13; i++) { + if (cmdline[i] <= ' ') { + break; + } + name[i] = cmdline[i]; + } + name[i] = 0; /*暂且将文件名的后面置为0*/ + + /*寻找文件 */ + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + if (finfo == 0 && name[i -1]!= '.') { + /*由于找不到文件,故在文件名后面加上“.hrb”后重新寻找*/ + name[i ] = '.'; + name[i + 1] = 'H'; + name[i + 2] = 'R'; + name[i + 3] = 'B'; + name[i + 4] = 0; + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + } + + if (finfo != 0) { + /*找到文件的情况*/ + p = (char *) memman_alloc_4k(memman, finfo->size); + file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); + if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) { + segsiz = *((int *) (p + 0x0000)); + esp = *((int *) (p + 0x000c)); + datsiz = *((int *) (p + 0x0010)); + dathrb = *((int *) (p + 0x0014)); + q = (char *) memman_alloc_4k(memman, segsiz); + *((int *) 0xfe8) = (int) q; + set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); + set_segmdesc(gdt + 1004, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); + for (i = 0; i < datsiz; i++) { + q[esp + i] = p[dathrb + i]; + } + start_app(0x1b, 1003 * 8, esp, 1004 * 8, &(task->tss.esp0)); + shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + for (i = 0; i < MAX_SHEETS; i++) { + sht = &(shtctl->sheets0[i]); + if (sht->flags != 0 && sht->task == task) { + /*找到被应用程序遗留的窗口*/ + sheet_free(sht); /*关闭*/ + } + } + memman_free_4k(memman, (int) q, segsiz); + } else { + cons_putstr0(cons, ".hrb file format error.\n"); + } + memman_free_4k(memman, (int) p, finfo->size); + cons_newline(cons); + return 1; + } + /*没有找到文件的情况*/ + return 0; +} + +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) +{ + int ds_base = *((int *) 0xfe8); + struct TASK *task = task_now(); + struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec); + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct SHEET *sht; + int *reg = &eax + 1; /* eax后面的地址*/ + /*强行改写通过PUSHAD保存的值*/ + /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */ + /* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ + int i; + + if (edx == 1) { + cons_putchar(cons, eax & 0xff, 1); + } else if (edx == 2) { + cons_putstr0(cons, (char *) ebx + ds_base); + } else if (edx == 3) { + cons_putstr1(cons, (char *) ebx + ds_base, ecx); + } else if (edx == 4) { + return &(task->tss.esp0); + } else if (edx == 5) { + sht = sheet_alloc(shtctl); + sht->task = task; + sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax); + make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0); + sheet_slide(sht, 100, 50); + sheet_updown(sht, 3); /*背景层高度3位于task_a之上*/ + reg[7] = (int) sht; + } else if (edx == 6) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + putfonts8_asc(sht->buf, sht->bxsize, esi, edi, eax, (char *) ebp + ds_base); + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + ecx * 8, edi + 16); + } + } else if (edx == 7) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + boxfill8(sht->buf, sht->bxsize, ebp, eax, ecx, esi, edi); + if ((ebx & 1) == 0) { + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 8) { + memman_init((struct MEMMAN *) (ebx + ds_base)); + ecx &= 0xfffffff0; /*以16字节为单位*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 9) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + reg[7] = memman_alloc((struct MEMMAN *) (ebx + ds_base), ecx); + } else if (edx == 10) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 11) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + sht->buf[sht->bxsize * edi + esi] = eax; + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + 1, edi + 1); + } + } else if (edx == 12) { + sht = (struct SHEET *) ebx; + sheet_refresh(sht, eax, ecx, esi, edi); + } else if (edx == 13) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + hrb_api_linewin(sht, eax, ecx, esi, edi, ebp); + if ((ebx & 1) == 0) { + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 14) { + sheet_free((struct SHEET *) ebx); + } else if (edx == 15) { + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + if (eax != 0) { + task_sleep(task); /* FIFO为空,休眠并等待*/ + } else { + io_sti(); + reg[7] = -1; + return 0; + } + } + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1) { /*光标用定时器*/ + /*应用程序运行时不需要显示光标,因此总是将下次显示用的值置为1*/ + timer_init(cons->timer, &task->fifo, 1); /*下次置为1*/ + timer_settime(cons->timer, 50); + } + if (i == 2) { /*光标ON */ + cons->cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + cons->cur_c = -1; + } + if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/ + reg[7] = i - 256; + return 0; + } + } + } + return 0; +} + +int *inthandler0c(int *esp) +{ + struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec); + struct TASK *task = task_now(); + char s[30]; + cons_putstr0(cons, "\nINT 0C :\n Stack Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +int *inthandler0d(int *esp) +{ + struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec); + struct TASK *task = task_now(); + char s[30]; + cons_putstr0(cons, "\nINT 0D :\n General Protected Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col) +{ + int i, x, y, len, dx, dy; + + dx = x1 - x0; + dy = y1 - y0; + x = x0 << 10; + y = y0 << 10; + if (dx < 0) { + dx = - dx; + } + if (dy < 0) { + dy = - dy; + } + if (dx >= dy) { + len = dx + 1; + if (x0 > x1) { + dx = -1024; + } else { + dx = 1024; + } + if (y0 <= y1) { + dy = ((y1 - y0 + 1) << 10) / len; + } else { + dy = ((y1 - y0 - 1) << 10) / len; + } + } else { + len = dy + 1; + if (y0 > y1) { + dy = -1024; + } else { + dy = 1024; + } + if (x0 <= x1) { + dx = ((x1 - x0 + 1) << 10) / len; + } else { + dx = ((x1 - x0 - 1) << 10) / len; + } + } + + for (i = 0; i < len; i++) { + sht->buf[(y >> 10) * sht->bxsize + (x >> 10)] = col; + x += dx; + y += dy; + } + + return; +} diff --git a/24_day/dsctbl.c b/24_day/dsctbl.c new file mode 100644 index 0000000..05bfe89 --- /dev/null +++ b/24_day/dsctbl.c @@ -0,0 +1,60 @@ +/* GDT、IDT、descriptor table 关系处理 */ + +#include "bootpack.h" + +void init_gdtidt(void) +{ + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *) ADR_IDT; + int i; + + /* GDT初始化 */ + for (i = 0; i <= LIMIT_GDT / 8; i++) { + set_segmdesc(gdt + i, 0, 0, 0); + } + set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW); + set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER); + load_gdtr(LIMIT_GDT, ADR_GDT); + + /* IDT初始化 */ + for (i = 0; i <= LIMIT_IDT / 8; i++) { + set_gatedesc(idt + i, 0, 0, 0); + } + load_idtr(LIMIT_IDT, ADR_IDT); + + /* IDT设置*/ + set_gatedesc(idt + 0x0c, (int) asm_inthandler0c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x0d, (int) asm_inthandler0d, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x27, (int) asm_inthandler27, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x40, (int) asm_hrb_api, 2 * 8, AR_INTGATE32 + 0x60); + + return; +} + +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar) +{ + if (limit > 0xfffff) { + ar |= 0x8000; /* G_bit = 1 */ + limit /= 0x1000; + } + sd->limit_low = limit & 0xffff; + sd->base_low = base & 0xffff; + sd->base_mid = (base >> 16) & 0xff; + sd->access_right = ar & 0xff; + sd->limit_high = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0); + sd->base_high = (base >> 24) & 0xff; + return; +} + +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar) +{ + gd->offset_low = offset & 0xffff; + gd->selector = selector; + gd->dw_count = (ar >> 8) & 0xff; + gd->access_right = ar & 0xff; + gd->offset_high = (offset >> 16) & 0xffff; + return; +} diff --git a/24_day/fifo.c b/24_day/fifo.c new file mode 100644 index 0000000..8f28f4b --- /dev/null +++ b/24_day/fifo.c @@ -0,0 +1,63 @@ +/* FIFO */ + +#include "bootpack.h" + +#define FLAGS_OVERRUN 0x0001 + +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task) +/* FIFO缓冲区的初始化*/ +{ + fifo->size = size; + fifo->buf = buf; + fifo->free = size; /*空*/ + fifo->flags = 0; + fifo->p = 0; /*写入位置*/ + fifo->q = 0; /*读取位置*/ + fifo->task = task; /*有数据写入时需要唤醒的任务*/ + return; +} + +int fifo32_put(struct FIFO32 *fifo, int data) +/*向FIFO写入数据并累积起来*/ +{ + if (fifo->free == 0) { + /*没有空余空间,溢出*/ + fifo->flags |= FLAGS_OVERRUN; + return -1; + } + fifo->buf[fifo->p] = data; + fifo->p++; + if (fifo->p == fifo->size) { + fifo->p = 0; + } + fifo->free--; + if (fifo->task != 0) { + if (fifo->task->flags != 2) { /*如果任务处于休眠状态*/ + task_run(fifo->task, -1, 0); /*将任务唤醒*/ + } + } + return 0; +} + +int fifo32_get(struct FIFO32 *fifo) +/*从FIFO取得一个数据*/ +{ + int data; + if (fifo->free == fifo->size) { + /*当缓冲区为空的情况下返回-1*/ + return -1; + } + data = fifo->buf[fifo->q]; + fifo->q++; + if (fifo->q == fifo->size) { + fifo->q = 0; + } + fifo->free++; + return data; +} + +int fifo32_status(struct FIFO32 *fifo) +/*报告已经存储了多少数据*/ +{ + return fifo->size - fifo->free; +} diff --git a/24_day/file.c b/24_day/file.c new file mode 100644 index 0000000..c289350 --- /dev/null +++ b/24_day/file.c @@ -0,0 +1,74 @@ +/* 文件相关函数 */ + +#include "bootpack.h" + +void file_readfat(int *fat, unsigned char *img) +/*将磁盘映像中的FAT解压缩 */ +{ + int i, j = 0; + for (i = 0; i < 2880; i += 2) { + fat[i + 0] = (img[j + 0] | img[j + 1] << 8) & 0xfff; + fat[i + 1] = (img[j + 1] >> 4 | img[j + 2] << 4) & 0xfff; + j += 3; + } + return; +} + +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img) +{ + int i; + for (;;) { + if (size <= 512) { + for (i = 0; i < size; i++) { + buf[i] = img[clustno * 512 + i]; + } + break; + } + for (i = 0; i < 512; i++) { + buf[i] = img[clustno * 512 + i]; + } + size -= 512; + buf += 512; + clustno = fat[clustno]; + } + return; +} + +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max) +{ + int i, j; + char s[12]; + for (j = 0; j < 11; j++) { + s[j] = ' '; + } + j = 0; + for (i = 0; name[i] != 0; i++) { + if (j >= 11) { return 0; /*没有找到*/ } + if (name[i] == '.' && j <= 8) { + j = 8; + } else { + s[j] = name[i]; + if ('a' <= s[j] && s[j] <= 'z') { + /*将小写字母转换为大写字母*/ + s[j] -= 0x20; + } + j++; + } + } + for (i = 0; i < max; ) { + if (finfo[i].name[0] == 0x00) { + break; + } + if ((finfo[i].type & 0x18) == 0) { + for (j = 0; j < 11; j++) { + if (finfo[i].name[j] != s[j]) { + goto next; + } + } + return finfo + i; /*找到文件*/ + } + next: + i++; + } + return 0; /*没有找到*/ +} diff --git a/24_day/graphic.c b/24_day/graphic.c new file mode 100644 index 0000000..f2df123 --- /dev/null +++ b/24_day/graphic.c @@ -0,0 +1,157 @@ +/* 关于绘图部分的处理 */ + +#include "bootpack.h" + +void init_palette(void) +{ + static unsigned char table_rgb[16 * 3] = { + 0x00, 0x00, 0x00, /* 0:黑 */ + 0xff, 0x00, 0x00, /* 1:梁红 */ + 0x00, 0xff, 0x00, /* 2:亮绿 */ + 0xff, 0xff, 0x00, /* 3:亮黄 */ + 0x00, 0x00, 0xff, /* 4:亮蓝 */ + 0xff, 0x00, 0xff, /* 5:亮紫 */ + 0x00, 0xff, 0xff, /* 6:浅亮蓝 */ + 0xff, 0xff, 0xff, /* 7:白 */ + 0xc6, 0xc6, 0xc6, /* 8:亮灰 */ + 0x84, 0x00, 0x00, /* 9:暗红 */ + 0x00, 0x84, 0x00, /* 10:暗绿 */ + 0x84, 0x84, 0x00, /* 11:暗黄 */ + 0x00, 0x00, 0x84, /* 12:暗青 */ + 0x84, 0x00, 0x84, /* 13:暗紫 */ + 0x00, 0x84, 0x84, /* 14:浅暗蓝 */ + 0x84, 0x84, 0x84 /* 15:暗灰 */ + }; + set_palette(0, 15, table_rgb); + return; + + /* C语言中的static char语句只能用于数据,相当于汇编中的DB指令 */ +} + +void set_palette(int start, int end, unsigned char *rgb) +{ + int i, eflags; + eflags = io_load_eflags(); /* 记录中断许可标志的值 */ + io_cli(); /* 将中断许可标志置为0,禁止中断 */ + io_out8(0x03c8, start); + for (i = start; i <= end; i++) { + io_out8(0x03c9, rgb[0] / 4); + io_out8(0x03c9, rgb[1] / 4); + io_out8(0x03c9, rgb[2] / 4); + rgb += 3; + } + io_store_eflags(eflags); /* 复原中断许可标志 */ + return; +} + +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) +{ + int x, y; + for (y = y0; y <= y1; y++) { + for (x = x0; x <= x1; x++) + vram[y * xsize + x] = c; + } + return; +} + +void init_screen8(char *vram, int x, int y) +{ + boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28); + boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1); + + boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24); + boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4); + boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4); + boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5); + boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3); + boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3); + + boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24); + boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4); + boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3); + boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3); + return; +} + +void putfont8(char *vram, int xsize, int x, int y, char c, char *font) +{ + int i; + char *p, d /* data */; + for (i = 0; i < 16; i++) { + p = vram + (y + i) * xsize + x; + d = font[i]; + if ((d & 0x80) != 0) { p[0] = c; } + if ((d & 0x40) != 0) { p[1] = c; } + if ((d & 0x20) != 0) { p[2] = c; } + if ((d & 0x10) != 0) { p[3] = c; } + if ((d & 0x08) != 0) { p[4] = c; } + if ((d & 0x04) != 0) { p[5] = c; } + if ((d & 0x02) != 0) { p[6] = c; } + if ((d & 0x01) != 0) { p[7] = c; } + } + return; +} + +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s) +{ + extern char hankaku[4096]; + /* C语言中,字符串都是以0x00结尾 */ + for (; *s != 0x00; s++) { + putfont8(vram, xsize, x, y, c, hankaku + *s * 16); + x += 8; + } + return; +} + +void init_mouse_cursor8(char *mouse, char bc) +/* 鼠标的数据准备(16x16) */ +{ + static char cursor[16][16] = { + "**************..", + "*OOOOOOOOOOO*...", + "*OOOOOOOOOO*....", + "*OOOOOOOOO*.....", + "*OOOOOOOO*......", + "*OOOOOOO*.......", + "*OOOOOOO*.......", + "*OOOOOOOO*......", + "*OOOO**OOO*.....", + "*OOO*..*OOO*....", + "*OO*....*OOO*...", + "*O*......*OOO*..", + "**........*OOO*.", + "*..........*OOO*", + "............*OO*", + ".............***" + }; + int x, y; + + for (y = 0; y < 16; y++) { + for (x = 0; x < 16; x++) { + if (cursor[y][x] == '*') { + mouse[y * 16 + x] = COL8_000000; + } + if (cursor[y][x] == 'O') { + mouse[y * 16 + x] = COL8_FFFFFF; + } + if (cursor[y][x] == '.') { + mouse[y * 16 + x] = bc; + } + } + } + return; +} + +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize) +{ + int x, y; + for (y = 0; y < pysize; y++) { + for (x = 0; x < pxsize; x++) { + vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x]; + } + } + return; +} diff --git a/24_day/hankaku.txt b/24_day/hankaku.txt new file mode 100644 index 0000000..62d56f9 --- /dev/null +++ b/24_day/hankaku.txt @@ -0,0 +1,4609 @@ +OSASK̔ptHg𗬗p + +char 0x00 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x01 +........ +........ +..***... +.*...*.. +*.....*. +*.*.*.*. +*.*.*.*. +*.....*. +*.....*. +*.*.*.*. +*..*..*. +.*...*.. +..***... +........ +........ +........ + +char 0x02 +........ +........ +..***... +.*****.. +*******. +**.*.**. +**.*.**. +*******. +*******. +**.*.**. +***.***. +.*****.. +..***... +........ +........ +........ + +char 0x03 +........ +........ +........ +........ +.**.**.. +*******. +*******. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x04 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x05 +........ +........ +........ +........ +...*.... +..***... +.*.*.*.. +*******. +.*.*.*.. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x06 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +**.*.**. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x07 +........ +........ +........ +........ +........ +........ +...**... +..****.. +..****.. +...**... +........ +........ +........ +........ +........ +........ + +char 0x08 +******** +******** +******** +******** +******** +******** +***..*** +**....** +**....** +***..*** +******** +******** +******** +******** +******** +******** + +char 0x09 +........ +........ +........ +........ +........ +..****.. +.**..**. +.*....*. +.*....*. +.**..**. +..****.. +........ +........ +........ +........ +........ + +char 0x0a +******** +******** +******** +******** +******** +**....** +*..**..* +*.****.* +*.****.* +*..**..* +**....** +******** +******** +******** +******** +******** + +char 0x0b +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x0c +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ + +char 0x0d +........ +........ +....**.. +....***. +....*.** +....*.** +....*.*. +....*... +....*... +...**... +.****... +*****... +.***.... +........ +........ +........ + +char 0x0e +........ +........ +...***** +...***** +...*...* +...*...* +...*...* +...*...* +...*...* +...*...* +.***.*** +******** +.**..**. +........ +........ +........ + +char 0x0f +........ +........ +........ +........ +...*.... +.*.*.*.. +..***... +..*.*... +..***... +.*.*.*.. +...*.... +........ +........ +........ +........ +........ + +char 0x10 +........ +*....... +**...... +***..... +****.... +*****... +******.. +*******. +******.. +*****... +****.... +***..... +**...... +*....... +........ +........ + +char 0x11 +........ +......*. +.....**. +....***. +...****. +..*****. +.******. +*******. +.******. +..*****. +...****. +....***. +.....**. +......*. +........ +........ + +char 0x12 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ +........ + +char 0x13 +........ +........ +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +........ +........ +.*...*.. +.*...*.. +........ +........ + +char 0x14 +........ +..*****. +.*..*.*. +*...*.*. +*...*.*. +*...*.*. +*...*.*. +.*..*.*. +..***.*. +....*.*. +....*.*. +....*.*. +....*.*. +....*.*. +........ +........ + +char 0x15 +.*****.. +*.....*. +.*...... +..*..... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +....*... +.....*.. +*.....*. +.*****.. +........ + +char 0x16 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*******. +*******. +........ +........ + +char 0x17 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +.*****.. +........ +........ + +char 0x18 +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x19 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ + +char 0x1a +........ +........ +........ +........ +...*.... +....*... +.....*.. +*******. +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ + +char 0x1b +........ +........ +........ +........ +...*.... +..*..... +.*...... +*******. +.*...... +..*..... +...*.... +........ +........ +........ +........ +........ + +char 0x1c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*....... +*....... +*******. +........ +........ + +char 0x1d +........ +........ +........ +........ +........ +..*.*... +.*...*.. +*******. +.*...*.. +..*.*... +........ +........ +........ +........ +........ +........ + +char 0x1e +........ +........ +........ +........ +...*.... +...*.... +..***... +..***... +.*****.. +.*****.. +*******. +*******. +........ +........ +........ +........ + +char 0x1f +........ +........ +........ +........ +*******. +*******. +.*****.. +.*****.. +..***... +..***... +...*.... +...*.... +........ +........ +........ +........ + +char 0x20 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x21 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ +...*.... +...*.... +........ +........ + +char 0x22 +..*.*... +..*.*... +..*.*... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x23 +........ +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +........ +........ + +char 0x24 +...*.... +..***.*. +.*.*.**. +*..*..*. +*..*..*. +*..*.... +.*.*.... +..***... +...*.*.. +...*..*. +*..*..*. +*..*..*. +**.*.*.. +*.***... +...*.... +...*.... + +char 0x25 +.**...*. +*..*..*. +*..*.*.. +*..*.*.. +.**.*... +....*... +...*.... +...*.... +..*..... +..*.**.. +.*.*..*. +.*.*..*. +*..*..*. +*...**.. +........ +........ + +char 0x26 +........ +.***.... +*...*... +*...*... +*...*... +*..*.... +.**..... +.*...*** +*.*...*. +*..*..*. +*...*.*. +*....*.. +.*...**. +..***..* +........ +........ + +char 0x27 +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x28 +......*. +.....*.. +....*... +....*... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....*... +....*... +.....*.. +......*. +........ + +char 0x29 +*....... +.*...... +..*..... +..*..... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..*..... +..*..... +.*...... +*....... +........ + +char 0x2a +........ +........ +........ +........ +........ +...*.... +*..*..*. +.*.*.*.. +..***... +.*.*.*.. +*..*..*. +...*.... +........ +........ +........ +........ + +char 0x2b +........ +........ +........ +........ +........ +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ +........ +........ + +char 0x2c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x2d +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ +........ +........ +........ +........ +........ +........ + +char 0x2e +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x2f +......*. +......*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*...... +.*...... +*....... +*....... + +char 0x30 +........ +...**... +..*..*.. +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +...**... +........ +........ + +char 0x31 +........ +....*... +...**... +..*.*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +..*****. +........ +........ + +char 0x32 +........ +...**... +..*..*.. +.*....*. +.*....*. +......*. +.....*.. +....*... +...*.... +..*..... +..*..... +.*...... +.*...... +.******. +........ +........ + +char 0x33 +........ +...**... +..*..*.. +.*....*. +......*. +......*. +.....*.. +...**... +.....*.. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x34 +........ +....**.. +....**.. +....**.. +...*.*.. +...*.*.. +...*.*.. +..*..*.. +..*..*.. +.*...*.. +.******. +.....*.. +.....*.. +...****. +........ +........ + +char 0x35 +........ +.*****.. +.*...... +.*...... +.*...... +.*.**... +.**..*.. +......*. +......*. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x36 +........ +...**... +..*..*.. +.*....*. +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x37 +........ +.******. +.*....*. +.*....*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x38 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x39 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..**. +...**.*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x3a +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x3b +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x3c +........ +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +........ + +char 0x3d +........ +........ +........ +........ +........ +........ +*******. +........ +........ +*******. +........ +........ +........ +........ +........ +........ + +char 0x3e +........ +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +........ + +char 0x3f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.....*.. +....*... +...*.... +...*.... +........ +........ +...**... +...**... +........ +........ + +char 0x40 +........ +..***... +.*...*.. +*.....*. +*..**.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*..***.. +*....... +.*...**. +..***... +........ +........ + +char 0x41 +........ +...**... +...**... +...**... +...**... +..*..*.. +..*..*.. +..*..*.. +..*..*.. +.******. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x42 +........ +****.... +.*..*... +.*...*.. +.*...*.. +.*...*.. +.*..*... +.****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +*****... +........ +........ + +char 0x43 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*....... +*....... +*....... +*.....*. +.*....*. +.*...*.. +..***... +........ +........ + +char 0x44 +........ +*****... +.*...*.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...*.. +.*...*.. +*****... +........ +........ + +char 0x45 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x46 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...*.. +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x47 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*..****. +*.....*. +*.....*. +*.....*. +.*....*. +.*...**. +..***... +........ +........ + +char 0x48 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.******. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x49 +........ +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x4a +........ +...***** +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +*....*.. +.*..*... +..**.... +........ + +char 0x4b +........ +***..*** +.*....*. +.*...*.. +.*..*... +.*.*.... +.*.*.... +.**..... +.*.*.... +.*.*.... +.*..*... +.*...*.. +.*....*. +***..*** +........ +........ + +char 0x4c +........ +****.... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x4d +........ +**....** +.*....*. +.**..**. +.**..**. +.**..**. +.*.**.*. +.*.**.*. +.*.**.*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x4e +........ +**...*** +.*....*. +.**...*. +.**...*. +.*.*..*. +.*.*..*. +.*.*..*. +.*..*.*. +.*..*.*. +.*..*.*. +.*...**. +.*...**. +***...*. +........ +........ + +char 0x4f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x50 +........ +*****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +.****... +.*...... +.*...... +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x51 +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*..*..*. +*...*.*. +.*...*.. +..***.*. +........ +........ + +char 0x52 +........ +******.. +.*....*. +.*....*. +.*....*. +.*....*. +.*****.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x53 +........ +..***.*. +.*...**. +*.....*. +*.....*. +*....... +.*...... +..***... +.....*.. +......*. +*.....*. +*.....*. +**...*.. +*.***... +........ +........ + +char 0x54 +........ +*******. +*..*..*. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x55 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..****.. +........ +........ + +char 0x56 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...**... +...**... +........ +........ + +char 0x57 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x58 +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +..*..*.. +..*..*.. +..*..*.. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x59 +........ +***.***. +.*...*.. +.*...*.. +.*...*.. +..*.*... +..*.*... +..*.*... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x5a +........ +*******. +*....*.. +*....*.. +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*....*. +*.....*. +*******. +........ +........ + +char 0x5b +........ +..*****. +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*****. +........ + +char 0x5c +*....... +*....... +.*...... +.*...... +..*..... +..*..... +..*..... +...*.... +...*.... +....*... +....*... +.....*.. +.....*.. +.....*.. +......*. +......*. + +char 0x5d +........ +.*****.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.*****.. +........ + +char 0x5e +........ +...*.... +..*.*... +.*...*.. +*.....*. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x5f +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ + +char 0x60 +...*.... +....*... +.....*.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x61 +........ +........ +........ +........ +........ +.***.... +....*... +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +*...**.. +.***.**. +........ +........ + +char 0x62 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +........ +........ + +char 0x63 +........ +........ +........ +........ +........ +..**.... +.*..**.. +*....*.. +*....*.. +*....... +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x64 +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.**. +........ +........ + +char 0x65 +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +******.. +*....... +*.....*. +.*....*. +..****.. +........ +........ + +char 0x66 +....***. +...*.... +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x67 +........ +........ +........ +........ +........ +..**.**. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +.....*.. +.****... + +char 0x68 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x69 +........ +...*.... +...*.... +........ +........ +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6a +........ +.....*.. +.....*.. +........ +........ +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +....*... +....*... +..**.... + +char 0x6b +**...... +.*...... +.*...... +.*...... +.*...... +.*..***. +.*...*.. +.*..*... +.*.*.... +.**..... +.*.*.... +.*..*... +.*...*.. +***..**. +........ +........ + +char 0x6c +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6d +........ +........ +........ +........ +........ +****.**. +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +**.**.** +........ +........ + +char 0x6e +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x6f +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x70 +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +.*...... +***..... + +char 0x71 +........ +........ +........ +........ +........ +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +....***. + +char 0x72 +........ +........ +........ +........ +........ +**.***.. +.**...*. +.*....*. +.*...... +.*...... +.*...... +.*...... +.*...... +***..... +........ +........ + +char 0x73 +........ +........ +........ +........ +........ +.****.*. +*....**. +*.....*. +**...... +..***... +.....**. +*.....*. +**....*. +*.****.. +........ +........ + +char 0x74 +........ +........ +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....***. +........ +........ + +char 0x75 +........ +........ +........ +........ +........ +**...**. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...**. +..***.** +........ +........ + +char 0x76 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +........ +........ + +char 0x77 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x78 +........ +........ +........ +........ +........ +**...**. +.*...*.. +..*.*... +..*.*... +...*.... +..*.*... +..*.*... +.*...*.. +**...**. +........ +........ + +char 0x79 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...*.... +...*.... +.**..... + +char 0x7a +........ +........ +........ +........ +........ +*******. +*.....*. +*....*.. +....*... +...*.... +..*..... +.*....*. +*.....*. +*******. +........ +........ + +char 0x7b +........ +.....**. +....*... +...*.... +...*.... +...*.... +...*.... +.**..... +...*.... +...*.... +...*.... +...*.... +....*... +.....**. +........ +........ + +char 0x7c +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0x7d +........ +.**..... +...*.... +....*... +....*... +....*... +....*... +.....**. +....*... +....*... +....*... +....*... +...*.... +.**..... +........ +........ + +char 0x7e +........ +.***..*. +*...**.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x7f +........ +........ +........ +........ +...*.... +..*.*... +.*...*.. +*.....*. +*******. +*.....*. +*******. +........ +........ +........ +........ +........ + +char 0x80 +........ +..***... +.*...*.. +*.....*. +*....... +*....... +*....... +*....... +*....... +*....... +*....... +*.....*. +.*...*.. +..***... +...*.... +..*..... + +char 0x81 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x82 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x83 +........ +...*.... +..*.*... +.*...*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x84 +........ +........ +..*..*.. +..*..*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x85 +...*.... +....*... +.....*.. +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x86 +........ +...**... +..*..*.. +...**... +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x87 +........ +........ +........ +........ +........ +..****.. +.*....*. +*....... +*....... +*....... +*....... +*....... +.*....*. +..****.. +....*... +...*.... + +char 0x88 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x89 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8a +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8b +........ +........ +..*..*.. +..*..*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8c +........ +...*.... +..*.*... +.*...*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8d +...*.... +....*... +.....*.. +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8e +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x8f +........ +..***... +.*...*.. +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x90 +....**.. +....*... +...*.... +*******. +*....... +*....... +*....... +*....... +*****... +*....... +*....... +*....... +*....... +*******. +........ +........ + +char 0x91 +........ +........ +........ +........ +........ +.**..... +...***.. +...*..*. +.***..*. +*..****. +*..*.... +*..*.... +*..*..*. +.**.**.. +........ +........ + +char 0x92 +....**.. +...*.... +..*..... +..*.*... +..*.*... +..*.*... +*******. +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +........ +........ + +char 0x93 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x94 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x95 +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x96 +........ +...*.... +..*.*... +.*...*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x97 +...*.... +....*... +.....*.. +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x98 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +.*...*.. +.*...*.. +..*.*... +..*.*... +...*.... +...*.... +..*..... +..*..... +.*...... + +char 0x99 +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9a +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9b +........ +..*.*... +..*.*... +..*.*... +..****.. +.**.*.*. +*.*.*... +*.*.*... +*.*.*... +*.*.*... +*.*.*... +.**.*.*. +..****.. +..*.*... +..*.*... +..*.*... + +char 0x9c +........ +....**.. +...*..*. +..*..... +..*..... +..*..... +******.. +..*..... +..*..... +..*..... +.**..... +*.*..... +*.**..*. +.*..**.. +........ +........ + +char 0x9d +........ +*.....*. +*.....*. +.*...*.. +..*.*... +...*.... +*******. +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x9e +........ +***..... +*..*.... +*...*... +*...*... +*...*... +*..*.*.. +***..*.. +*..***** +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +........ +........ + +char 0x9f +........ +....**.. +...*..*. +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +...*.... +*..*.... +.**..... +........ +........ + +char 0xa0 +....**.. +....*... +...*.... +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0xa1 +....**.. +....*... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xa2 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa3 +....**.. +....*... +...*.... +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0xa4 +........ +...*..*. +..*.*.*. +..*..*.. +........ +*****... +*....*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0xa5 +...*..*. +..*.*.*. +..*..*.. +........ +*.....*. +**....*. +**....*. +*.*...*. +*..*..*. +*..*..*. +*...*.*. +*....**. +*....**. +*.....*. +........ +........ + +char 0xa6 +........ +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +*******. +........ +........ + +char 0xa7 +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +*******. +........ +........ + +char 0xa8 +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +..*..... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*....... +*....... +*....... +........ +........ + +char 0xaa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +......*. +......*. +......*. +........ +........ + +char 0xab +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +.****... +.....*.. +..***... +.*...... +.*****.. +........ +........ + +char 0xac +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +...**... +..*.*... +.*..*... +.*****.. +....*... +........ +........ + +char 0xad +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xae +........ +........ +........ +........ +...*..*. +..*..*.. +.*..*... +*..*.... +*..*.... +.*..*... +..*..*.. +...*..*. +........ +........ +........ +........ + +char 0xaf +........ +........ +........ +........ +*..*.... +.*..*... +..*..*.. +...*..*. +...*..*. +..*..*.. +.*..*... +*..*.... +........ +........ +........ +........ + +char 0xb0 +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. + +char 0xb1 +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. + +char 0xb2 +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* + +char 0xb3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb6 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb7 +........ +........ +........ +........ +........ +........ +........ +******.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb8 +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb9 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xba +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbb +........ +........ +........ +........ +........ +........ +........ +******.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +******.. +........ +........ +........ +........ +........ +........ + +char 0xbd +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******.. +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xbe +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +........ +........ +........ +........ +........ +........ + +char 0xbf +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc0 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc1 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc4 +........ +........ +........ +........ +........ +........ +........ +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc6 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xc8 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xc9 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xca +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xcb +........ +........ +........ +........ +........ +........ +........ +******** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcd +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xce +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcf +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xd0 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd1 +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd3 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xd5 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd6 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd8 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd9 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xda +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xdb +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdc +........ +........ +........ +........ +........ +........ +........ +........ +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdd +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... + +char 0xde +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** + +char 0xdf +******** +******** +******** +******** +******** +******** +******** +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xea +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xeb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xec +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xed +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xee +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xef +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfc +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfd +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfe +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xff +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ diff --git a/24_day/hello.nas b/24_day/hello.nas new file mode 100644 index 0000000..b4e9576 --- /dev/null +++ b/24_day/hello.nas @@ -0,0 +1,16 @@ +[INSTRSET "i486p"] +[BITS 32] + MOV ECX,msg + MOV EDX,1 +putloop: + MOV AL,[CS:ECX] + CMP AL,0 + JE fin + INT 0x40 + ADD ECX,1 + JMP putloop +fin: + MOV EDX,4 + INT 0x40 +msg: + DB "hello",0 diff --git a/24_day/hello2.nas b/24_day/hello2.nas new file mode 100644 index 0000000..5e1e58c --- /dev/null +++ b/24_day/hello2.nas @@ -0,0 +1,9 @@ +[INSTRSET "i486p"] +[BITS 32] + MOV EDX,2 + MOV EBX,msg + INT 0x40 + MOV EDX,4 + INT 0x40 +msg: + DB "hello",0 diff --git a/24_day/hello3.c b/24_day/hello3.c new file mode 100644 index 0000000..97d3236 --- /dev/null +++ b/24_day/hello3.c @@ -0,0 +1,12 @@ +void api_putchar(int c); +void api_end(void); + +void HariMain(void) +{ + api_putchar('h'); + api_putchar('e'); + api_putchar('l'); + api_putchar('l'); + api_putchar('o'); + api_end(); +} diff --git a/24_day/hello4.c b/24_day/hello4.c new file mode 100644 index 0000000..7fb73de --- /dev/null +++ b/24_day/hello4.c @@ -0,0 +1,8 @@ +void api_putstr0(char *s); +void api_end(void); + +void HariMain(void) +{ + api_putstr0("hello, world\n"); + api_end(); +} diff --git a/24_day/hello5.nas b/24_day/hello5.nas new file mode 100644 index 0000000..ee62330 --- /dev/null +++ b/24_day/hello5.nas @@ -0,0 +1,20 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "hello5.nas"] + + GLOBAL _HariMain + +[SECTION .text] + +_HariMain: + MOV EDX,2 + MOV EBX,msg + INT 0x40 + MOV EDX,4 + INT 0x40 + +[SECTION .data] + +msg: + DB "hello, world", 0x0a, 0 diff --git a/24_day/int.c b/24_day/int.c new file mode 100644 index 0000000..c717372 --- /dev/null +++ b/24_day/int.c @@ -0,0 +1,37 @@ +/*初始化关系 */ + +#include "bootpack.h" +#include + +void init_pic(void) +/* PIC初始化 */ +{ + io_out8(PIC0_IMR, 0xff ); /* 禁止所有中断 */ + io_out8(PIC1_IMR, 0xff ); /* 禁止所有中断 */ + + io_out8(PIC0_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC0_ICW2, 0x20 ); /* IRQ0-7由INT20-27接收 */ + io_out8(PIC0_ICW3, 1 << 2); /* PIC1由IRQ2相连 */ + io_out8(PIC0_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC1_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC1_ICW2, 0x28 ); /* IRQ8-15由INT28-2f接收 */ + io_out8(PIC1_ICW3, 2 ); /* PIC1由IRQ2连接 */ + io_out8(PIC1_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外全部禁止 */ + io_out8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中断 */ + + return; +} + +void inthandler27(int *esp) +/* PIC0中断的不完整策略 */ +/* 这个中断在Athlon64X2上通过芯片组提供的便利,只需执行一次 */ +/* 这个中断只是接收,不执行任何操作 */ +/* 为什么不处理? + → 因为这个中断可能是电气噪声引发的、只是处理一些重要的情况。*/ +{ + io_out8(PIC0_OCW2, 0x67); /* 通知PIC的IRQ-07(参考7-1) */ + return; +} diff --git a/24_day/ipl10.nas b/24_day/ipl10.nas new file mode 100644 index 0000000..7108a21 --- /dev/null +++ b/24_day/ipl10.nas @@ -0,0 +1,109 @@ +; haribote-ipl +; TAB=4 + +CYLS EQU 10 ; 声明CYLS=10 + + ORG 0x7c00 ; 指明程序装载地址 + +; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code + + JMP entry + DB 0x90 + DB "HARIBOTE" ; 启动扇区名称(8字节) + DW 512 ; 每个扇区(sector)大小(必须512字节) + DB 1 ; 簇(cluster)大小(必须为1个扇区) + DW 1 ; FAT起始位置(一般为第一个扇区) + DB 2 ; FAT个数(必须为2) + DW 224 ; 根目录大小(一般为224项) + DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512) + DB 0xf0 ; 磁盘类型(必须为0xf0) + DW 9 ; FAT的长度(必??9扇区) + DW 18 ; 一个磁道(track)有几个扇区(必须为18) + DW 2 ; 磁头数(必??2) + DD 0 ; 不使用分区,必须是0 + DD 2880 ; 重写一次磁盘大小 + DB 0,0,0x29 ; 意义不明(固定) + DD 0xffffffff ; (可能是)卷标号码 + DB "HARIBOTEOS " ; 磁盘的名称(必须为11字?,不足填空格) + DB "FAT12 " ; 磁盘格式名称(必??8字?,不足填空格) + RESB 18 ; 先空出18字节 + +; 程序主体 + +entry: + MOV AX,0 ; 初始化寄存器 + MOV SS,AX + MOV SP,0x7c00 + MOV DS,AX + +; 读取磁盘 + + MOV AX,0x0820 + MOV ES,AX + MOV CH,0 ; 柱面0 + MOV DH,0 ; 磁头0 + MOV CL,2 ; 扇区2 + +readloop: + MOV SI,0 ; 记录失败次数寄存器 + +retry: + MOV AH,0x02 ; AH=0x02 : 读入磁盘 + MOV AL,1 ; 1个扇区 + MOV BX,0 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 调用磁盘BIOS + JNC next ; 没出错则跳转到fin + ADD SI,1 ; 往SI加1 + CMP SI,5 ; 比较SI与5 + JAE error ; SI >= 5 跳转到error + MOV AH,0x00 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 重置驱动器 + JMP retry +next: + MOV AX,ES ; 把内存地址后移0x200(512/16十六进制转换) + ADD AX,0x0020 + MOV ES,AX ; ADD ES,0x020因为没有ADD ES,只能通过AX进行 + ADD CL,1 ; 往CL里面加1 + CMP CL,18 ; 比较CL与18 + JBE readloop ; CL <= 18 跳转到readloop + MOV CL,1 + ADD DH,1 + CMP DH,2 + JB readloop ; DH < 2 跳转到readloop + MOV DH,0 + ADD CH,1 + CMP CH,CYLS + JB readloop ; CH < CYLS 跳转到readloop + +; 读取完毕,跳转到haribote.sys执行! + MOV [0x0ff0],CH ; IPLがどこまで読んだのかをメモ + JMP 0xc200 + +error: + MOV SI,msg + +putloop: + MOV AL,[SI] + ADD SI,1 ; 给SI加1 + CMP AL,0 + JE fin + MOV AH,0x0e ; 显示一个文字 + MOV BX,15 ; 指定字符颜色 + INT 0x10 ; 调用显卡BIOS + JMP putloop + +fin: + HLT ; 让CPU停止,等待指令 + JMP fin ; 无限循环 + +msg: + DB 0x0a, 0x0a ; 换行两次 + DB "load error" + DB 0x0a ; 换行 + DB 0 + + RESB 0x7dfe-$ ; 填写0x00直到0x001fe + + DB 0x55, 0xaa diff --git a/24_day/keyboard.c b/24_day/keyboard.c new file mode 100644 index 0000000..eb5140a --- /dev/null +++ b/24_day/keyboard.c @@ -0,0 +1,44 @@ +/* 键盘控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *keyfifo; +int keydata0; + +void inthandler21(int *esp) +{ + int data; + io_out8(PIC0_OCW2, 0x61); /* 把IRQ-01接收信号结束的信息通知给PIC */ + data = io_in8(PORT_KEYDAT); + fifo32_put(keyfifo, data + keydata0); + return; +} + +#define PORT_KEYSTA 0x0064 +#define KEYSTA_SEND_NOTREADY 0x02 +#define KEYCMD_WRITE_MODE 0x60 +#define KBC_MODE 0x47 + +void wait_KBC_sendready(void) +{ + /* 等待键盘控制电路准备完毕 */ + for (;;) { + if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) { + break; + } + } + return; +} + +void init_keyboard(struct FIFO32 *fifo, int data0) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + keyfifo = fifo; + keydata0 = data0; + /* 键盘控制器的初始化 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, KBC_MODE); + return; +} diff --git a/24_day/lines.c b/24_day/lines.c new file mode 100644 index 0000000..83e7ceb --- /dev/null +++ b/24_day/lines.c @@ -0,0 +1,29 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +void api_closewin(int win); +int api_getkey(int mode); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win, i; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "lines"); + for (i = 0; i < 8; i++) { + api_linewin(win + 1, 8, 26, 77, i * 9 + 26, i); + api_linewin(win + 1, 88, 26, i * 9 + 88, 89, i); + } + api_refreshwin(win, 6, 26, 154, 90); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_closewin(win); + api_end(); +} diff --git a/24_day/make.bat b/24_day/make.bat new file mode 100644 index 0000000..e489766 --- /dev/null +++ b/24_day/make.bat @@ -0,0 +1 @@ +..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/24_day/memory.c b/24_day/memory.c new file mode 100644 index 0000000..54a447a --- /dev/null +++ b/24_day/memory.c @@ -0,0 +1,162 @@ +/* �������֌W */ + +#include "bootpack.h" + +#define EFLAGS_AC_BIT 0x00040000 +#define CR0_CACHE_DISABLE 0x60000000 + +unsigned int memtest(unsigned int start, unsigned int end) +{ + char flg486 = 0; + unsigned int eflg, cr0, i; + + /* 确认CPU是386还是486以上的 */ + eflg = io_load_eflags(); + eflg |= EFLAGS_AC_BIT; /* AC-bit = 1 */ + io_store_eflags(eflg); + eflg = io_load_eflags(); + if ((eflg & EFLAGS_AC_BIT) != 0) { + /* 如果是386,即使设定AC=1,AC的值还会自动回到0 */ + flg486 = 1; + } + + eflg &= ~EFLAGS_AC_BIT; /* AC-bit = 0 */ + io_store_eflags(eflg); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 |= CR0_CACHE_DISABLE; /* 禁止缓存 */ + store_cr0(cr0); + } + + i = memtest_sub(start, end); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 &= ~CR0_CACHE_DISABLE; /* 允许缓存 */ + store_cr0(cr0); + } + + return i; +} + +void memman_init(struct MEMMAN *man) +{ + man->frees = 0; /* 可用信息数目 */ + man->maxfrees = 0; /* 用于观察可用状况:frees的最大值 */ + man->lostsize = 0; /* 释放失败的内存的大小总和 */ + man->losts = 0; /* 释放失败次数 */ + return; +} + +unsigned int memman_total(struct MEMMAN *man) +/* 报告空余内存大小的合计 */ +{ + unsigned int i, t = 0; + for (i = 0; i < man->frees; i++) { + t += man->free[i].size; + } + return t; +} + +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size) +/* 分配 */ +{ + unsigned int i, a; + for (i = 0; i < man->frees; i++) { + if (man->free[i].size >= size) { + /* 找到了足够大的内存 */ + a = man->free[i].addr; + man->free[i].addr += size; + man->free[i].size -= size; + if (man->free[i].size == 0) { + /* 如果free[i]变成了0,就减掉一条可用信息 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 代入结构体 */ + } + } + return a; + } + } + return 0; /* 没有可用空间 */ +} + +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size) +/* 释放 */ +{ + int i, j; + /* 为便于归纳内存,将free[]按照addr的顺序排列 */ + /* 所以,先决定应该放在哪里 */ + for (i = 0; i < man->frees; i++) { + if (man->free[i].addr > addr) { + break; + } + } + /* free[i - 1].addr < addr < free[i].addr */ + if (i > 0) { + /* 前面有可用内存 */ + if (man->free[i - 1].addr + man->free[i - 1].size == addr) { + /* 可以与前面的可用内存归纳到一起 */ + man->free[i - 1].size += size; + if (i < man->frees) { + /* 后面也有 */ + if (addr + size == man->free[i].addr) { + /* 也可以与后面的可用内存归纳到一起 */ + man->free[i - 1].size += man->free[i].size; + /* man->free[i]删除 */ + /* free[i]变成0后归纳到前面去 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 结构体赋值 */ + } + } + } + return 0; /* 成功完成 */ + } + } + /* 不能与前面的可用空间归纳到一起 */ + if (i < man->frees) { + /* 后面还有 */ + if (addr + size == man->free[i].addr) { + /* 可以与后面的内容归纳到一起 */ + man->free[i].addr = addr; + man->free[i].size += size; + return 0; /* 成功完成 */ + } + } + /* 既不能与前面归纳到一起,也不能与后面归纳到一起 */ + if (man->frees < MEMMAN_FREES) { + /* free[i]之后的,向后移动,腾出一点可用空间 */ + for (j = man->frees; j > i; j--) { + man->free[j] = man->free[j - 1]; + } + man->frees++; + if (man->maxfrees < man->frees) { + man->maxfrees = man->frees; /* 更新最大值 */ + } + man->free[i].addr = addr; + man->free[i].size = size; + return 0; /* 成功完成 */ + } + /* 不能往后移动 */ + man->losts++; + man->lostsize += size; + return -1; /* 失败 */ +} + +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size) +{ + unsigned int a; + size = (size + 0xfff) & 0xfffff000; + a = memman_alloc(man, size); + return a; +} + +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size) +{ + int i; + size = (size + 0xfff) & 0xfffff000; + i = memman_free(man, addr, size); + return i; +} diff --git a/24_day/mouse.c b/24_day/mouse.c new file mode 100644 index 0000000..0c6403e --- /dev/null +++ b/24_day/mouse.c @@ -0,0 +1,76 @@ +/* 鼠标控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *mousefifo; +int mousedata0; + +void inthandler2c(int *esp) +/* 来自PS/2鼠标的中断 */ +{ + int data; + io_out8(PIC1_OCW2, 0x64); /* 把IRQ-12接收信号结束的信息通知给PIC1 */ + io_out8(PIC0_OCW2, 0x62); /* 把IRQ-02接收信号结束的信息通知给PIC0 */ + data = io_in8(PORT_KEYDAT); + fifo32_put(mousefifo, data + mousedata0); + return; +} + +#define KEYCMD_SENDTO_MOUSE 0xd4 +#define MOUSECMD_ENABLE 0xf4 + +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + mousefifo = fifo; + mousedata0 = data0; + /* 鼠标有效 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, MOUSECMD_ENABLE); + /* 顺利的话,ACK(0xfa)会被发送*/ + mdec->phase = 0; /* 等待鼠标的0xfa的阶段*/ +return; +} + +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat) +{ + if (mdec->phase == 0) { + /* 等待鼠标的0xfa的阶段 */ + if (dat == 0xfa) { + mdec->phase = 1; + } + return 0; + } + if (mdec->phase == 1) { + /* 等待鼠标第一字节的阶段 */ + mdec->buf[0] = dat; + mdec->phase = 2; + return 0; + } + if (mdec->phase == 2) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[1] = dat; + mdec->phase = 3; + return 0; + } + if (mdec->phase == 3) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[2] = dat; + mdec->phase = 1; + mdec->btn = mdec->buf[0] & 0x07; + mdec->x = mdec->buf[1]; + mdec->y = mdec->buf[2]; + if ((mdec->buf[0] & 0x10) != 0) { + mdec->x |= 0xffffff00; + } + if ((mdec->buf[0] & 0x20) != 0) { + mdec->y |= 0xffffff00; + } + mdec->y = - mdec->y; /* 鼠标的y方向与画面符号相反 */ + return 1; + } + /* 应该不可能到这里来 */ + return -1; +} diff --git a/24_day/mtask.c b/24_day/mtask.c new file mode 100644 index 0000000..b518641 --- /dev/null +++ b/24_day/mtask.c @@ -0,0 +1,201 @@ +/* 多任务管理 */ + +#include "bootpack.h" + +struct TASKCTL *taskctl; +struct TIMER *task_timer; + +struct TASK *task_now(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + return tl->tasks[tl->now]; +} + +void task_add(struct TASK *task) +{ + struct TASKLEVEL *tl = &taskctl->level[task->level]; + tl->tasks[tl->running] = task; + tl->running++; + task->flags = 2; /*活动中*/ + return; +} + +void task_remove(struct TASK *task) +{ + int i; + struct TASKLEVEL *tl = &taskctl->level[task->level]; + + /*寻找task所在的位置*/ + for (i = 0; i < tl->running; i++) { + if (tl->tasks[i] == task) { + /*在这里 */ + break; + } + } + + tl->running--; + if (i < tl->now) { + tl->now--; /*需要移动成员,要相应地处理 */ + } + if (tl->now >= tl->running) { + /*如果now的值出现异常,则进行修正*/ + tl->now = 0; + } + task->flags = 1; /* 休眠中 */ + + /* 移动 */ + for (; i < tl->running; i++) { + tl->tasks[i] = tl->tasks[i + 1]; + } + return; +} + +void task_switchsub(void) +{ + int i; + /*寻找最上层的LEVEL */ + for (i = 0; i < MAX_TASKLEVELS; i++) { + if (taskctl->level[i].running > 0) { + break; /*找到了*/ + } + } + taskctl->now_lv = i; + taskctl->lv_change = 0; + return; +} + +void task_idle(void) +{ + for (;;) { + io_hlt(); + } +} + +struct TASK *task_init(struct MEMMAN *memman) +{ + int i; + struct TASK *task, *idle; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + + + taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL)); + for (i = 0; i < MAX_TASKS; i++) { + taskctl->tasks0[i].flags = 0; + taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8; + set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32); + } + for (i = 0; i < MAX_TASKLEVELS; i++) { + taskctl->level[i].running = 0; + taskctl->level[i].now = 0; + } + + task = task_alloc(); + task->flags = 2; /*活动中标志*/ + task->priority = 2; /* 0.02秒*/ + task->level = 0; /*最高LEVEL */ + task_add(task); + task_switchsub(); /* LEVEL 设置*/ + load_tr(task->sel); + task_timer = timer_alloc(); + timer_settime(task_timer, task->priority); + + idle = task_alloc(); + idle->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024; + idle->tss.eip = (int) &task_idle; + idle->tss.es = 1 * 8; + idle->tss.cs = 2 * 8; + idle->tss.ss = 1 * 8; + idle->tss.ds = 1 * 8; + idle->tss.fs = 1 * 8; + idle->tss.gs = 1 * 8; + task_run(idle, MAX_TASKLEVELS - 1, 1); + + return task; +} + +struct TASK *task_alloc(void) +{ + int i; + struct TASK *task; + for (i = 0; i < MAX_TASKS; i++) { + if (taskctl->tasks0[i].flags == 0) { + task = &taskctl->tasks0[i]; + task->flags = 1; /*正在使用的标志*/ + task->tss.eflags = 0x00000202; /* IF = 1; */ + task->tss.eax = 0; /*这里先置为0*/ + task->tss.ecx = 0; + task->tss.edx = 0; + task->tss.ebx = 0; + task->tss.ebp = 0; + task->tss.esi = 0; + task->tss.edi = 0; + task->tss.es = 0; + task->tss.ds = 0; + task->tss.fs = 0; + task->tss.gs = 0; + task->tss.ldtr = 0; + task->tss.iomap = 0x40000000; + task->tss.ss0 = 0; + return task; + } + } + return 0; /*全部正在使用*/ +} + +void task_run(struct TASK *task, int level, int priority) +{ + if (level < 0) { + level = task->level; /*不改变LEVEL */ + } + if (priority > 0) { + task->priority = priority; + } + if (task->flags == 2 && task->level != level) { + /*改变活动中的LEVEL */ + task_remove(task); /*这里执行之后flag的值会变为1,于是下面的if语句块也会被执行*/ + } + if (task->flags != 2) { + /*从休眠状态唤醒的情形*/ + task->level = level; + task_add(task); + } + taskctl->lv_change = 1; /*下次任务切换时检查LEVEL */ + return; +} + +void task_switch(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + struct TASK *new_task, *now_task = tl->tasks[tl->now]; + tl->now++; + if (tl->now == tl->running) { + tl->now = 0; + } + if (taskctl->lv_change != 0) { + task_switchsub(); + tl = &taskctl->level[taskctl->now_lv]; + } + new_task = tl->tasks[tl->now]; + timer_settime(task_timer, new_task->priority); + if (new_task != now_task) { + farjmp(0, new_task->sel); + } + return; +} + +void task_sleep(struct TASK *task) +{ + struct TASK *now_task; + if (task->flags == 2) { + /*如果处于活动状态*/ + now_task = task_now(); + task_remove(task); /*执行此语句的话flags将变为1 */ + if (task == now_task) { + /*如果是让自己休眠,则需要进行任务切换*/ + task_switchsub(); + now_task = task_now(); /*在设定后获取当前任务的值*/ + farjmp(0, now_task->sel); + } + } + return; +} diff --git a/24_day/naskfunc.nas b/24_day/naskfunc.nas new file mode 100644 index 0000000..d32a472 --- /dev/null +++ b/24_day/naskfunc.nas @@ -0,0 +1,307 @@ +; naskfunc +; TAB=4 + +[FORMAT "WCOFF"] ; 制作目标文件的模式 +[INSTRSET "i486p"] ; 使用到486为止的指令 +[BITS 32] ; 3制作32位模式用的机器语言 +[FILE "naskfunc.nas"] ; 文件名 + + GLOBAL _io_hlt, _io_cli, _io_sti, _io_stihlt + GLOBAL _io_in8, _io_in16, _io_in32 + GLOBAL _io_out8, _io_out16, _io_out32 + GLOBAL _io_load_eflags, _io_store_eflags + GLOBAL _load_gdtr, _load_idtr + GLOBAL _load_cr0, _store_cr0 + GLOBAL _load_tr + GLOBAL _asm_inthandler20, _asm_inthandler21 + GLOBAL _asm_inthandler27, _asm_inthandler2c + GLOBAL _asm_inthandler0c, _asm_inthandler0d + GLOBAL _asm_end_app, _memtest_sub + GLOBAL _farjmp, _farcall + GLOBAL _asm_hrb_api, _start_app + EXTERN _inthandler20, _inthandler21 + EXTERN _inthandler27, _inthandler2c + EXTERN _inthandler0c, _inthandler0d + EXTERN _hrb_api + +[SECTION .text] + +_io_hlt: ; void io_hlt(void); + HLT + RET + +_io_cli: ; void io_cli(void); + CLI + RET + +_io_sti: ; void io_sti(void); + STI + RET + +_io_stihlt: ; void io_stihlt(void); + STI + HLT + RET + +_io_in8: ; int io_in8(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AL,DX + RET + +_io_in16: ; int io_in16(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AX,DX + RET + +_io_in32: ; int io_in32(int port); + MOV EDX,[ESP+4] ; port + IN EAX,DX + RET + +_io_out8: ; void io_out8(int port, int data); + MOV EDX,[ESP+4] ; port + MOV AL,[ESP+8] ; data + OUT DX,AL + RET + +_io_out16: ; void io_out16(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,AX + RET + +_io_out32: ; void io_out32(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,EAX + RET + +_io_load_eflags: ; int io_load_eflags(void); + PUSHFD ; PUSH EFLAGS + POP EAX + RET + +_io_store_eflags: ; void io_store_eflags(int eflags); + MOV EAX,[ESP+4] + PUSH EAX + POPFD ; POP EFLAGS + RET + +_load_gdtr: ; void load_gdtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LGDT [ESP+6] + RET + +_load_idtr: ; void load_idtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LIDT [ESP+6] + RET + +_load_cr0: ; int load_cr0(void); + MOV EAX,CR0 + RET + +_store_cr0: ; void store_cr0(int cr0); + MOV EAX,[ESP+4] + MOV CR0,EAX + RET + +_load_tr: ; void load_tr(int tr); + LTR [ESP+4] ; tr + RET + +_asm_inthandler20: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler20 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler21: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler21 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler27: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler27 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler2c: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler2c + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler0c: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0c + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; 在INT 0x0c中也需要这句 + IRETD + +_asm_inthandler0d: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0d + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; INT 0x0d需要这句 + IRETD + +_memtest_sub: ; unsigned int memtest_sub(unsigned int start, unsigned int end) + PUSH EDI ; (由于还要使用EBX, ESI, EDI) + PUSH ESI + PUSH EBX + MOV ESI,0xaa55aa55 ; pat0 = 0xaa55aa55; + MOV EDI,0x55aa55aa ; pat1 = 0x55aa55aa; + MOV EAX,[ESP+12+4] ; i = start; +mts_loop: + MOV EBX,EAX + ADD EBX,0xffc ; p = i + 0xffc; + MOV EDX,[EBX] ; old = *p; + MOV [EBX],ESI ; *p = pat0; + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP EDI,[EBX] ; if (*p != pat1) goto fin; + JNE mts_fin + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP ESI,[EBX] ; if (*p != pat0) goto fin; + JNE mts_fin + MOV [EBX],EDX ; *p = old; + ADD EAX,0x1000 ; i += 0x1000; + CMP EAX,[ESP+12+8] ; if (i <= end) goto mts_loop; + JBE mts_loop + POP EBX + POP ESI + POP EDI + RET +mts_fin: + MOV [EBX],EDX ; *p = old; + POP EBX + POP ESI + POP EDI + RET + +_farjmp: ; void farjmp(int eip, int cs); + JMP FAR [ESP+4] ; eip, cs + RET + +_farcall: ; void farcall(int eip, int cs); + CALL FAR [ESP+4] ; eip, cs + RET + +_asm_hrb_api: + STI + PUSH DS + PUSH ES + PUSHAD ; 用于保存的PUSH + PUSHAD ; 用于向hrb_api传值的PUSH + MOV AX,SS + MOV DS,AX ; 将操作系统用段地址存入DS和ES + MOV ES,AX + CALL _hrb_api + CMP EAX,0 ; 当EAX不为0时程序结束 + JNE _asm_end_app + ADD ESP,32 + POPAD + POP ES + POP DS + IRETD +_asm_end_app: +; EAX为tss.esp0的地址 + MOV ESP,[EAX] + MOV DWORD [EAX+4],0 + POPAD + RET ; 返回cmd_app + +_start_app: ; void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); + PUSHAD ; 将32位寄存器的值全部保存起来 + MOV EAX,[ESP+36] ; 应用程序用EIP + MOV ECX,[ESP+40] ; 应用程序用CS + MOV EDX,[ESP+44] ; 应用程序用ESP + MOV EBX,[ESP+48] ; 应用程序用DS/SS + MOV EBP,[ESP+52] ; tss.esp0的地址 + MOV [EBP ],ESP ; 保存操作系统用ESP + MOV [EBP+4],SS ; 保存操作系统用SS + MOV ES,BX + MOV DS,BX + MOV FS,BX + MOV GS,BX +; 下面调整栈,以免用RETF跳转到应用程序 + OR ECX,3 ; 将应用程序用段号和3进行OR运算 + OR EBX,3 ; 将应用程序用段号和3进行OR运算 + PUSH EBX ; 应用程序的SS + PUSH EDX ; 应用程序的ESP + PUSH ECX ; 应用程序的CS + PUSH EAX ; 应用程序的EIP + RETF +; 应用程序结束后不会回到这里 diff --git a/24_day/sheet.c b/24_day/sheet.c new file mode 100644 index 0000000..a51c756 --- /dev/null +++ b/24_day/sheet.c @@ -0,0 +1,217 @@ +/* sheet */ + +#include "bootpack.h" + +#define SHEET_USE 1 + +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize) +{ + struct SHTCTL *ctl; + int i; + ctl = (struct SHTCTL *) memman_alloc_4k(memman, sizeof (struct SHTCTL)); + if (ctl == 0) { + goto err; + } + ctl->map = (unsigned char *) memman_alloc_4k(memman, xsize * ysize); + if (ctl->map == 0) { + memman_free_4k(memman, (int) ctl, sizeof (struct SHTCTL)); + goto err; + } + ctl->vram = vram; + ctl->xsize = xsize; + ctl->ysize = ysize; + ctl->top = -1; /* 没有一张SHEET */ + for (i = 0; i < MAX_SHEETS; i++) { + ctl->sheets0[i].flags = 0; /* 标记为未使用 */ + ctl->sheets0[i].ctl = ctl; /* 记录所属*/ + } +err: + return ctl; +} + +struct SHEET *sheet_alloc(struct SHTCTL *ctl) +{ + struct SHEET *sht; + int i; + for (i = 0; i < MAX_SHEETS; i++) { + if (ctl->sheets0[i].flags == 0) { + sht = &ctl->sheets0[i]; + sht->flags = SHEET_USE; /* 标记为正在使用*/ + sht->height = -1; /* 隐藏 */ + sht->task = 0; /*不使用自动关闭功能*/ + return sht; + } + } + return 0; /* 所有的SHEET都处于正在使用状态*/ +} + +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv) +{ + sht->buf = buf; + sht->bxsize = xsize; + sht->bysize = ysize; + sht->col_inv = col_inv; + return; +} + +void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1; + unsigned char *buf, sid, *map = ctl->map; + struct SHEET *sht; + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= ctl->top; h++) { + sht = ctl->sheets[h]; + sid = sht - ctl->sheets0; /* 将进行了减法计算的地址作为图层号码使用 */ + buf = sht->buf; + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } + if (by1 > sht->bysize) { by1 = sht->bysize; } + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (buf[by * sht->bxsize + bx] != sht->col_inv) { + map[vy * ctl->xsize + vx] = sid; + } + } + } + } + return; +} + +void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0, int h1) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1; + unsigned char *buf, *vram = ctl->vram, *map = ctl->map, sid; + struct SHEET *sht; + + /* 如果refresh的范围超出了画面则修正 */ + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= h1; h++) { + sht = ctl->sheets[h]; + buf = sht->buf; + sid = sht - ctl->sheets0; + + /* 使用vx0~vy1,对bx0~by1进行倒推 */ + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } /* 处理刷新范围在图层外侧 */ + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } /* 应对不同的重叠方式 */ + if (by1 > sht->bysize) { by1 = sht->bysize; } + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + } + } + return; +} + +void sheet_updown(struct SHEET *sht, int height) +{ + struct SHTCTL *ctl = sht->ctl; + int h, old = sht->height; /* 存储设置前的高度信息 */ + if (height > ctl->top + 1) { + height = ctl->top + 1; + } + if (height < -1) { + height = -1; + } + sht->height = height;/* 设定高度 */ + + /* 下面主要是进行sheets[]的重新排列 */ + if (old > height) { /* 比以前低 */ + if (height >= 0) { + /* 把中间的往上提 */ + for (h = old; h > height; h--) { + ctl->sheets[h] = ctl->sheets[h - 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1, old); + } else { /* 隐藏 */ + if (ctl->top > old) { + /* 把上面的降下来 */ + for (h = old; h < ctl->top; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + } + ctl->top--; /* 由于显示中的图层减少了一个,所以最上面的图层高度下降 */ + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0, old - 1); + } + } else if (old < height) { /* 比以前高 */ + if (old >= 0) { + /* 把中间的拉下去 */ + for (h = old; h < height; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + } else { /* 由隐藏状态转为显示状态 */ + /* 将已在上面的提上来 */ + for (h = ctl->top; h >= height; h--) { + ctl->sheets[h + 1] = ctl->sheets[h]; + ctl->sheets[h + 1]->height = h + 1; + } + ctl->sheets[height] = sht; + ctl->top++; /* 由于已显示的图层增加了1个,所以最上面的图层高度增加 */ + } + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height, height); /* 按新图层信息重新绘制画面 */ + } + return; +} + +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1) +{ + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面*/ + sheet_refreshsub(sht->ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1, sht->height, sht->height); + } + return; +} + +void sheet_slide(struct SHEET *sht, int vx0, int vy0) +{ + struct SHTCTL *ctl = sht->ctl; + int old_vx0 = sht->vx0, old_vy0 = sht->vy0; + sht->vx0 = vx0; + sht->vy0 = vy0; + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面 */ + sheet_refreshmap(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0); + sheet_refreshmap(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height); + sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0, sht->height - 1); + sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height, sht->height); + } + return; +} + +void sheet_free(struct SHEET *sht) +{ + if (sht->height >= 0) { + sheet_updown(sht, -1); /* 如果处于显示状态,则先设定为隐藏 */ + } + sht->flags = 0; /* "未使用"标志 */ + return; +} diff --git a/24_day/star1.c b/24_day/star1.c new file mode 100644 index 0000000..8d80ffa --- /dev/null +++ b/24_day/star1.c @@ -0,0 +1,18 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_point(int win, int x, int y, int col); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "star1"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + api_point(win, 75, 59, 3);/*黄色*/ + api_end(); +} diff --git a/24_day/stars.c b/24_day/stars.c new file mode 100644 index 0000000..dc38b2b --- /dev/null +++ b/24_day/stars.c @@ -0,0 +1,24 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_point(int win, int x, int y, int col); +void api_end(void); + +int rand(void); /*产生0~32767之间的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win, x, y, 3);/*黄色*/ + } + api_end(); +} diff --git a/24_day/stars2.c b/24_day/stars2.c new file mode 100644 index 0000000..94a029e --- /dev/null +++ b/24_day/stars2.c @@ -0,0 +1,26 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_point(int win, int x, int y, int col); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_end(void); + +int rand(void); /*产生0~32767的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars2"); + api_boxfilwin(win + 1, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win + 1, x, y, 3);/*黄色*/ + } + api_refreshwin(win, 6, 26, 144, 94); + api_end(); +} diff --git a/24_day/timer.c b/24_day/timer.c new file mode 100644 index 0000000..2c795f8 --- /dev/null +++ b/24_day/timer.c @@ -0,0 +1,118 @@ +/* 定时器 */ + +#include "bootpack.h" + +#define PIT_CTRL 0x0043 +#define PIT_CNT0 0x0040 + +struct TIMERCTL timerctl; + +#define TIMER_FLAGS_ALLOC 1 /* 已配置状态 */ +#define TIMER_FLAGS_USING 2 /* 定时器运行中 */ + +void init_pit(void) +{ + int i; + struct TIMER *t; + io_out8(PIT_CTRL, 0x34); + io_out8(PIT_CNT0, 0x9c); + io_out8(PIT_CNT0, 0x2e); + timerctl.count = 0; + for (i = 0; i < MAX_TIMER; i++) { + timerctl.timers0[i].flags = 0; /* 没有使用 */ + } + t = timer_alloc(); /* 取得一个 */ + t->timeout = 0xffffffff; + t->flags = TIMER_FLAGS_USING; + t->next = 0; /* 末尾 */ + timerctl.t0 = t; /* 因为现在只有哨兵,所以他就在最前面*/ + timerctl.next = 0xffffffff; /* 因为只有哨兵,所以下一个超时时刻就是哨兵的时刻 */ + return; +} + +struct TIMER *timer_alloc(void) +{ + int i; + for (i = 0; i < MAX_TIMER; i++) { + if (timerctl.timers0[i].flags == 0) { + timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; + return &timerctl.timers0[i]; + } + } + return 0; /* 没找到 */ +} + +void timer_free(struct TIMER *timer) +{ + timer->flags = 0; /* 未使用 */ + return; +} + +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data) +{ + timer->fifo = fifo; + timer->data = data; + return; +} + +void timer_settime(struct TIMER *timer, unsigned int timeout) +{ + int e; + struct TIMER *t, *s; + timer->timeout = timeout + timerctl.count; + timer->flags = TIMER_FLAGS_USING; + e = io_load_eflags(); + io_cli(); + t = timerctl.t0; + if (timer->timeout <= t->timeout) { + /* 插入最前面的情况 */ + timerctl.t0 = timer; + timer->next = t; /* 下面是设定t */ + timerctl.next = timer->timeout; + io_store_eflags(e); + return; + } + for (;;) { + s = t; + t = t->next; + if (timer->timeout <= t->timeout) { + /* 插入s和t之间的情况 */ + s->next = timer; /* s下一个是timer */ + timer->next = t; /* timer的下一个是t */ + io_store_eflags(e); + return; + } + } +} + +void inthandler20(int *esp) +{ + struct TIMER *timer; + char ts = 0; + io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00接收信号结束的信息通知给PIC */ + timerctl.count++; + if (timerctl.next > timerctl.count) { + return; + } + timer = timerctl.t0; /* 首先把最前面的地址赋给timer */ + for (;;) { + /* 因为timers的定时器都处于运行状态,所以不确认flags */ + if (timer->timeout > timerctl.count) { + break; + } + /* 超时 */ + timer->flags = TIMER_FLAGS_ALLOC; + if (timer != task_timer) { + fifo32_put(timer->fifo, timer->data); + } else { + ts = 1; /* mt_timer超时*/ + } + timer = timer->next; /* 将下一个定时器的地址赋给timer*/ + } + timerctl.t0 = timer; + timerctl.next = timer->timeout; + if (ts != 0) { + task_switch(); + } + return; +} diff --git a/24_day/walk.c b/24_day/walk.c new file mode 100644 index 0000000..6b106b4 --- /dev/null +++ b/24_day/walk.c @@ -0,0 +1,35 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +void api_closewin(int win); +int api_getkey(int mode); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "walk"); + api_boxfilwin(win, 4, 24, 155, 95, 0);/*黑色*/ + x = 76; + y = 56; + api_putstrwin(win, x, y, 3, 1, "*");/*黄色*/ + for (;;) { + i = api_getkey(1); + api_putstrwin(win, x, y, 0 , 1, "*"); /*用黑色擦除*/ + if (i == '4' && x > 4) { x -= 8; } + if (i == '6' && x < 148) { x += 8; } + if (i == '8' && y > 24) { y -= 8; } + if (i == '2' && y < 80) { y += 8; } + if (i == 0x0a) { break; } /*按回车键结束*/ + api_putstrwin(win, x, y, 3 , 1, "*");/*黄色*/ + } + api_closewin(win); + api_end(); +} diff --git a/24_day/window.c b/24_day/window.c new file mode 100644 index 0000000..ec625bb --- /dev/null +++ b/24_day/window.c @@ -0,0 +1,88 @@ +/* 窗口相关函数 */ + +#include "bootpack.h" + +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act) +{ + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, xsize - 1, 0 ); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, xsize - 2, 1 ); + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, 0, ysize - 1); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, 1, ysize - 2); + boxfill8(buf, xsize, COL8_848484, xsize - 2, 1, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, xsize - 1, 0, xsize - 1, ysize - 1); + boxfill8(buf, xsize, COL8_C6C6C6, 2, 2, xsize - 3, ysize - 3); + boxfill8(buf, xsize, COL8_848484, 1, ysize - 2, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, 0, ysize - 1, xsize - 1, ysize - 1); + make_wtitle8(buf, xsize, title, act); + return; +} + +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act) +{ + static char closebtn[14][16] = { + "OOOOOOOOOOOOOOO@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQQQ@@QQQQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "O$$$$$$$$$$$$$$@", + "@@@@@@@@@@@@@@@@" + }; + int x, y; + char c, tc, tbc; + if (act != 0) { + tc = COL8_FFFFFF; + tbc = COL8_000084; + } else { + tc = COL8_C6C6C6; + tbc = COL8_848484; + } + boxfill8(buf, xsize, tbc, 3, 3, xsize - 4, 20); + putfonts8_asc(buf, xsize, 24, 4, tc, title); + for (y = 0; y < 14; y++) { + for (x = 0; x < 16; x++) { + c = closebtn[y][x]; + if (c == '@') { + c = COL8_000000; + } else if (c == '$') { + c = COL8_848484; + } else if (c == 'Q') { + c = COL8_C6C6C6; + } else { + c = COL8_FFFFFF; + } + buf[(5 + y) * xsize + (xsize - 21 + x)] = c; + } + } + return; +} + +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l) +{ + boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15); + putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); + sheet_refresh(sht, x, y, x + l * 8, y + 16); + return; +} + +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c) +{ + int x1 = x0 + sx, y1 = y0 + sy; + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3); + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1); + boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0); + return; +} diff --git a/24_day/winhelo.c b/24_day/winhelo.c new file mode 100644 index 0000000..6d7fb0a --- /dev/null +++ b/24_day/winhelo.c @@ -0,0 +1,11 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_end(void); + +char buf[150 * 50]; + +void HariMain(void) +{ + int win; + win = api_openwin(buf, 150, 50, -1, "hello"); + api_end(); +} diff --git a/24_day/winhelo2.c b/24_day/winhelo2.c new file mode 100644 index 0000000..f00b007 --- /dev/null +++ b/24_day/winhelo2.c @@ -0,0 +1,15 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_end(void); + +char buf[150 * 50]; + +void HariMain(void) +{ + int win; + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 3); /*黄色*/ + api_putstrwin(win, 28, 28, 0 /*黑色*/, 12, "hello, world"); + api_end(); +} diff --git a/24_day/winhelo3.c b/24_day/winhelo3.c new file mode 100644 index 0000000..527ec01 --- /dev/null +++ b/24_day/winhelo3.c @@ -0,0 +1,19 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win; + + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 6); /*浅蓝色*/ + api_putstrwin(win, 28, 28, 0 , 12, "hello, world");/*黑色*/ + api_end(); +} \ No newline at end of file From 36da3e87a93bba11785e8b45e1a37454d0341685 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 11 May 2016 13:16:09 +0800 Subject: [PATCH 02/83] =?UTF-8?q?=E7=AA=97=E5=8F=A3=E5=88=87=E6=8D=A2?= =?UTF-8?q?=EF=BC=881=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 24_day/bootpack.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/24_day/bootpack.c b/24_day/bootpack.c index c0c9240..1642bd1 100644 --- a/24_day/bootpack.c +++ b/24_day/bootpack.c @@ -233,6 +233,9 @@ void HariMain(void) task_cons->tss.eip = (int) asm_end_app; io_sti(); } + if (i == 256 + 0x57 && shtctl->top > 2) { /* F11 */ + sheet_updown(shtctl->sheets[1], shtctl->top - 1); + } if (i == 256 + 0xfa) { /*键盘成功接收到数据*/ keycmd_wait = -1; } From 991da3f5694e3b455b4e2d2433da7fd2c0fd8377 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 11 May 2016 13:34:22 +0800 Subject: [PATCH 03/83] =?UTF-8?q?=E7=AA=97=E5=8F=A3=E5=88=87=E6=8D=A2?= =?UTF-8?q?=EF=BC=882=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 24_day/bootpack.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/24_day/bootpack.c b/24_day/bootpack.c index 1642bd1..15044bc 100644 --- a/24_day/bootpack.c +++ b/24_day/bootpack.c @@ -42,6 +42,8 @@ void HariMain(void) }; int key_to = 0, key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; struct CONSOLE *cons; + int j, x, y; + struct SHEET *sht; init_gdtidt(); init_pic(); @@ -265,10 +267,23 @@ void HariMain(void) if (my > binfo->scrny - 1) { my = binfo->scrny - 1; } + sheet_slide(sht_mouse, mx, my);/* 包含sheet_refresh含sheet_refresh */ + if ((mdec.btn & 0x01) != 0) { /* 按下左键、移动sht_win */ - sheet_slide(sht_win, mx - 80, my - 8); + for (j = shtctl->top - 1; j > 0; j--) { + sht = shtctl->sheets[j]; + x = mx - sht->vx0; + y = my - sht->vy0; + if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) { + if (sht->buf[y * sht->bxsize + x] != sht->col_inv) { + sheet_updown(sht, shtctl->top - 1); + break; + } + } + } } + } } else if (i <= 1) { /* 光标用定时器*/ if (i != 0) { From d77f778b8e9578d541d1884f10a930b924983ae6 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 11 May 2016 13:42:39 +0800 Subject: [PATCH 04/83] =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 24_day/bootpack.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/24_day/bootpack.c b/24_day/bootpack.c index 15044bc..541aa30 100644 --- a/24_day/bootpack.c +++ b/24_day/bootpack.c @@ -42,8 +42,8 @@ void HariMain(void) }; int key_to = 0, key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; struct CONSOLE *cons; - int j, x, y; - struct SHEET *sht; + int j, x, y, mmx = -1, mmy = -1; + struct SHEET *sht = 0; init_gdtidt(); init_pic(); @@ -267,21 +267,39 @@ void HariMain(void) if (my > binfo->scrny - 1) { my = binfo->scrny - 1; } - + sheet_slide(sht_mouse, mx, my);/* 包含sheet_refresh含sheet_refresh */ - if ((mdec.btn & 0x01) != 0) { /* 按下左键、移动sht_win */ - for (j = shtctl->top - 1; j > 0; j--) { - sht = shtctl->sheets[j]; - x = mx - sht->vx0; - y = my - sht->vy0; - if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) { - if (sht->buf[y * sht->bxsize + x] != sht->col_inv) { - sheet_updown(sht, shtctl->top - 1); - break; + if ((mdec.btn & 0x01) != 0) { /* 按下左键 */ + if (mmx < 0) { + /*如果处于通常模式*/ + /*按照从上到下的顺序寻找鼠标所指向的图层*/ + for (j = shtctl->top - 1; j > 0; j--) { + sht = shtctl->sheets[j]; + x = mx - sht->vx0; + y = my - sht->vy0; + if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) { + if (sht->buf[y * sht->bxsize + x] != sht->col_inv) { + sheet_updown(sht, shtctl->top - 1); + if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) { + mmx = mx; /*进入窗口移动模式*/ + mmy = my; + } + break; + } } } + } else { + /*如果处于窗口移动模式*/ + x = mx - mmx; /*计算鼠标的移动距离*/ + y = my - mmy; + sheet_slide(sht, sht->vx0 + x, sht->vy0 + y); + mmx = mx; /*更新为移动后的坐标*/ + mmy = my; } + } else { + /*没有按下左键*/ + mmx = -1; /*返回通常模式*/ } } From 826407144226d82598c8100b5e9da18d3836d407 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 11 May 2016 13:59:51 +0800 Subject: [PATCH 05/83] =?UTF-8?q?=E7=94=A8=E9=BC=A0=E6=A0=87=E5=85=B3?= =?UTF-8?q?=E9=97=AD=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 24_day/bootpack.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/24_day/bootpack.c b/24_day/bootpack.c index 541aa30..668bae3 100644 --- a/24_day/bootpack.c +++ b/24_day/bootpack.c @@ -285,6 +285,18 @@ void HariMain(void) mmx = mx; /*进入窗口移动模式*/ mmy = my; } + if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <=y && y < 19) { + /*点击“×”按钮*/ + if (sht->task != 0) { /*该窗口是否为应用程序窗口?*/ + cons = (struct CONSOLE *) *((int *) 0x0fec); + cons_putstr0(cons, "\nBreak(mouse) :\n"); + io_cli(); /*强制结束处理中禁止切换任务*/ + task_cons->tss.eax = (int) + &(task_cons->tss.esp0); + task_cons->tss.eip = (int) asm_end_app; + io_sti(); + } + } break; } } From bde8ac972b0900515589d49411084b7daa958d8d Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 11 May 2016 14:49:22 +0800 Subject: [PATCH 06/83] =?UTF-8?q?=E5=B0=86=E8=BE=93=E5=85=A5=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E5=88=B0=E5=BA=94=E7=94=A8=E7=A8=8B=E5=BA=8F=E7=AA=97?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 24_day/bootpack.c | 78 ++++++++++++++++++++++++++++++++--------------- 24_day/bootpack.h | 1 + 24_day/console.c | 3 +- 24_day/window.c | 30 ++++++++++++++++++ 4 files changed, 86 insertions(+), 26 deletions(-) diff --git a/24_day/bootpack.c b/24_day/bootpack.c index 668bae3..f24570d 100644 --- a/24_day/bootpack.c +++ b/24_day/bootpack.c @@ -5,6 +5,9 @@ #define KEYCMD_LED 0xed +int keywin_off(struct SHEET *key_win, struct SHEET *sht_win, int cur_c, int cur_x); +int keywin_on(struct SHEET *key_win, struct SHEET *sht_win, int cur_c); + void HariMain(void) { struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; @@ -40,10 +43,10 @@ void HariMain(void) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, '|', 0, 0 }; - int key_to = 0, key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; + int key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; struct CONSOLE *cons; int j, x, y, mmx = -1, mmy = -1; - struct SHEET *sht = 0; + struct SHEET *sht = 0, *key_win; init_gdtidt(); init_pic(); @@ -120,6 +123,9 @@ void HariMain(void) sheet_updown(sht_cons, 1); sheet_updown(sht_win, 2); sheet_updown(sht_mouse, 3); + key_win = sht_win; + sht_cons->task = task_cons; + sht_cons->flags |= 0x20; /*有光标*/ /*为了避免和键盘当前状态冲突,在一开始先进行设置*/ fifo32_put(&keycmd, KEYCMD_LED); @@ -139,6 +145,10 @@ void HariMain(void) } else { i = fifo32_get(&fifo); io_sti(); + if (key_win->flags == 0) { /*输入窗口被关闭*/ + key_win = shtctl->sheets[shtctl->top - 1]; + cursor_c = keywin_on(key_win, sht_win, cursor_c); + } if (256 <= i && i <= 511) { /* 键盘数据*/ if (i < 0x80 + 256) { /*将按键编码转换为字符编码*/ if (key_shift == 0) { @@ -155,7 +165,7 @@ void HariMain(void) } } if (s[0] != 0) { /*一般字符*/ - if (key_to == 0) { /*发送给任务A */ + if (key_win == sht_win) { /*发送给任务A */ if (cursor_x < 128) { /*显示一个字符之后将光标后移一位*/ s[1] = 0; @@ -163,42 +173,33 @@ void HariMain(void) cursor_x += 8; } } else { /*发送给命令行窗口*/ - fifo32_put(&task_cons->fifo, s[0] + 256); + fifo32_put(&key_win->task->fifo, s[0] + 256); } } if (i == 256 + 0x0e) { /* 退格键 */ - if (key_to == 0) { /*发送给任务A */ + if (key_win == sht_win) { /*发送给任务A */ if (cursor_x > 8) { /*用空白擦除光标后将光标前移一位*/ putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1); cursor_x -= 8; } } else { /*发送给命令行窗口*/ - fifo32_put(&task_cons->fifo, 8 + 256); + fifo32_put(&key_win->task->fifo, 8 + 256); } } if (i == 256 + 0x1c) { /*回车键*/ - if (key_to != 0) { /*发送至命令行窗口*/ - fifo32_put(&task_cons->fifo, 10 + 256); + if (key_win != sht_win) { /*发送至命令行窗口*/ + fifo32_put(&key_win->task->fifo, 10 + 256); } } - if (i == 256 + 0x0f) { /* Tab */ - if (key_to == 0) { - key_to = 1; - make_wtitle8(buf_win, sht_win->bxsize, "task_a", 0); - make_wtitle8(buf_cons, sht_cons->bxsize, "console", 1); - cursor_c = -1; /* 不显示光标 */ - boxfill8(sht_win->buf, sht_win->bxsize, COL8_FFFFFF, cursor_x, 28, cursor_x + 7, 43); - fifo32_put(&task_cons->fifo, 2); /*命令行窗口光标ON */ - } else { - key_to = 0; - make_wtitle8(buf_win, sht_win->bxsize, "task_a", 1); - make_wtitle8(buf_cons, sht_cons->bxsize, "console", 0); - cursor_c = COL8_000000; - fifo32_put(&task_cons->fifo, 3); /*命令行窗口光标OFF */ + if (i == 256 + 0x0f) { /* Tab键 */ + cursor_c = keywin_off(key_win, sht_win, cursor_c, cursor_x); + j = key_win->height - 1; + if (j == 0) { + j = shtctl->top - 1; } - sheet_refresh(sht_win, 0, 0, sht_win->bxsize, 21); - sheet_refresh(sht_cons, 0, 0, sht_cons->bxsize, 21); + key_win = shtctl->sheets[j]; + cursor_c = keywin_on(key_win, sht_win, cursor_c); } if (i == 256 + 0x2a) { /*左Shift ON */ key_shift |= 1; @@ -287,7 +288,7 @@ void HariMain(void) } if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <=y && y < 19) { /*点击“×”按钮*/ - if (sht->task != 0) { /*该窗口是否为应用程序窗口?*/ + if ((sht->flags & 0x10) != 0) { /*该窗口是否为应用程序窗口?*/ cons = (struct CONSOLE *) *((int *) 0x0fec); cons_putstr0(cons, "\nBreak(mouse) :\n"); io_cli(); /*强制结束处理中禁止切换任务*/ @@ -336,3 +337,30 @@ void HariMain(void) } } } + +int keywin_off(struct SHEET *key_win, struct SHEET *sht_win, int cur_c, int cur_x) +{ + change_wtitle8(key_win, 0); + if (key_win == sht_win) { + cur_c = -1; /*删除光标*/ + boxfill8(sht_win->buf, sht_win->bxsize, COL8_FFFFFF, cur_x, 28, cur_x + 7, 43); + } else { + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 3); /*命令行窗口光标OFF */ + } + } + return cur_c; +} + +int keywin_on(struct SHEET *key_win, struct SHEET *sht_win, int cur_c) +{ + change_wtitle8(key_win, 1); + if (key_win == sht_win) { + cur_c = COL8_000000; /*显示光标*/ + } else { + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 2); /*命令行窗口光标ON */ + } + } + return cur_c; +} diff --git a/24_day/bootpack.h b/24_day/bootpack.h index cea84d2..4215c38 100644 --- a/24_day/bootpack.h +++ b/24_day/bootpack.h @@ -233,6 +233,7 @@ void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char ac void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l); void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c); void make_wtitle8(unsigned char *buf, int xsize, char *title, char act); +void change_wtitle8(struct SHEET *sht, char act); /* console.c */ struct CONSOLE { diff --git a/24_day/console.c b/24_day/console.c index 37586b0..b9748b0 100644 --- a/24_day/console.c +++ b/24_day/console.c @@ -303,7 +303,7 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) shtctl = (struct SHTCTL *) *((int *) 0x0fe4); for (i = 0; i < MAX_SHEETS; i++) { sht = &(shtctl->sheets0[i]); - if (sht->flags != 0 && sht->task == task) { + if ((sht->flags & 0x11) == 0x11 && sht->task == task) { /*找到被应用程序遗留的窗口*/ sheet_free(sht); /*关闭*/ } @@ -344,6 +344,7 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int } else if (edx == 5) { sht = sheet_alloc(shtctl); sht->task = task; + sht->flags |= 0x10; sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax); make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0); sheet_slide(sht, 100, 50); diff --git a/24_day/window.c b/24_day/window.c index ec625bb..4d70578 100644 --- a/24_day/window.c +++ b/24_day/window.c @@ -86,3 +86,33 @@ void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c) boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0); return; } + +void change_wtitle8(struct SHEET *sht, char act) +{ + int x, y, xsize = sht->bxsize; + char c, tc_new, tbc_new, tc_old, tbc_old, *buf = sht->buf; + if (act != 0) { + tc_new = COL8_FFFFFF; + tbc_new = COL8_000084; + tc_old = COL8_C6C6C6; + tbc_old = COL8_848484; + } else { + tc_new = COL8_C6C6C6; + tbc_new = COL8_848484; + tc_old = COL8_FFFFFF; + tbc_old = COL8_000084; + } + for (y = 3; y <= 20; y++) { + for (x = 3; x <= xsize - 4; x++) { + c = buf[y * xsize + x]; + if (c == tc_old && x <= xsize - 22) { + c = tc_new; + } else if (c == tbc_old) { + c = tbc_new; + } + buf[y * xsize + x] = c; + } + } + sheet_refresh(sht, 3, 3, xsize, 21); + return; +} From b27c562b9841e76f578bf404d870abd1e3391a67 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 11 May 2016 14:57:20 +0800 Subject: [PATCH 07/83] =?UTF-8?q?=E7=94=A8=E9=BC=A0=E6=A0=87=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E8=BE=93=E5=85=A5=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 24_day/bootpack.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/24_day/bootpack.c b/24_day/bootpack.c index f24570d..0bff4b5 100644 --- a/24_day/bootpack.c +++ b/24_day/bootpack.c @@ -282,6 +282,11 @@ void HariMain(void) if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) { if (sht->buf[y * sht->bxsize + x] != sht->col_inv) { sheet_updown(sht, shtctl->top - 1); + if (sht != key_win) { + cursor_c = keywin_off(key_win, sht_win, cursor_c, cursor_x); + key_win = sht; + cursor_c = keywin_on(key_win, sht_win, cursor_c);/*到此结束*/ + } if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) { mmx = mx; /*进入窗口移动模式*/ mmy = my; From 9475d3d828b5abaecbadb4d50bc85f5d50c4d993 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 11 May 2016 15:24:10 +0800 Subject: [PATCH 08/83] =?UTF-8?q?=E5=AE=9A=E6=97=B6=E5=99=A8API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 24_day/Makefile | 10 +++++++++- 24_day/a_nask.nas | 35 +++++++++++++++++++++++++++++++++++ 24_day/console.c | 10 +++++++++- 24_day/noodle.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 24_day/noodle.c diff --git a/24_day/Makefile b/24_day/Makefile index b61f4a2..4e81e55 100644 --- a/24_day/Makefile +++ b/24_day/Makefile @@ -148,10 +148,17 @@ walk.bim : walk.obj a_nask.obj Makefile walk.hrb : walk.bim Makefile $(BIM2HRB) walk.bim walk.hrb 48k +noodle.bim : noodle.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:noodle.bim stack:1k map:noodle.map \ + noodle.obj a_nask.obj + +noodle.hrb : noodle.bim Makefile + $(BIM2HRB) noodle.bim noodle.hrb 40k + haribote.img : ipl10.bin haribote.sys Makefile \ hello.hrb hello2.hrb a.hrb hello3.hrb hello4.hrb hello5.hrb \ winhelo.hrb winhelo2.hrb winhelo3.hrb star1.hrb stars.hrb stars2.hrb \ - lines.hrb walk.hrb + lines.hrb walk.hrb noodle.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:ipl10.bin len:512 from:0 to:0 \ copy from:haribote.sys to:@: \ @@ -171,6 +178,7 @@ haribote.img : ipl10.bin haribote.sys Makefile \ copy from:stars2.hrb to:@: \ copy from:lines.hrb to:@: \ copy from:walk.hrb to:@: \ + copy from:noodle.hrb to:@: \ imgout:haribote.img # 其他指令 diff --git a/24_day/a_nask.nas b/24_day/a_nask.nas index bce3b4a..56fe642 100644 --- a/24_day/a_nask.nas +++ b/24_day/a_nask.nas @@ -17,6 +17,10 @@ GLOBAL _api_linewin GLOBAL _api_closewin GLOBAL _api_getkey + GLOBAL _api_alloctimer + GLOBAL _api_inittimer + GLOBAL _api_settimer + GLOBAL _api_freetimer [SECTION .text] @@ -186,3 +190,34 @@ _api_getkey: ; int api_getkey(int mode); MOV EAX,[ESP+4] ; mode INT 0x40 RET + +_api_alloctimer: ; int api_alloctimer(void); + MOV EDX,16 + INT 0x40 + RET + +_api_inittimer: ; void api_inittimer(int timer, int data); + PUSH EBX + MOV EDX,17 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; data + INT 0x40 + POP EBX + RET + +_api_settimer: ; void api_settimer(int timer, int time); + PUSH EBX + MOV EDX,18 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; time + INT 0x40 + POP EBX + RET + +_api_freetimer: ; void api_freetimer(int timer); + PUSH EBX + MOV EDX,19 + MOV EBX,[ESP+ 8] ; timer + INT 0x40 + POP EBX + RET diff --git a/24_day/console.c b/24_day/console.c index b9748b0..d61d65c 100644 --- a/24_day/console.c +++ b/24_day/console.c @@ -414,11 +414,19 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int if (i == 3) { /*光标OFF */ cons->cur_c = -1; } - if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/ + if (i >= 256) { /*键盘数据(通过任务A)等*/ reg[7] = i - 256; return 0; } } + } else if (edx == 16) { + reg[7] = (int) timer_alloc(); + } else if (edx == 17) { + timer_init((struct TIMER *) ebx, &task->fifo, eax + 256); + } else if (edx == 18) { + timer_settime((struct TIMER *) ebx, eax); + } else if (edx == 19) { + timer_free((struct TIMER *) ebx); } return 0; } diff --git a/24_day/noodle.c b/24_day/noodle.c new file mode 100644 index 0000000..13b9033 --- /dev/null +++ b/24_day/noodle.c @@ -0,0 +1,42 @@ +#include + +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +int api_getkey(int mode); +int api_alloctimer(void); +void api_inittimer(int timer, int data); +void api_settimer(int timer, int time); +void api_end(void); + +void HariMain(void) +{ + char *buf, s[12]; + int win, timer, sec = 0, min = 0, hou = 0; + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "noodle"); + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (;;) { + sprintf(s, "%5d:%02d:%02d", hou, min, sec); + api_boxfilwin(win, 28, 27, 115, 41, 7);/*白色*/ + api_putstrwin(win, 28, 27, 0, 11, s); /*黑色*/ + api_settimer(timer, 100); /* 1秒 */ + if (api_getkey(1) != 128) { + break; + } + sec++; + if (sec == 60) { + sec = 0; + min++; + if (min == 60) { + min = 0; + hou++; + } + } + } + api_end(); +} From efb6028e00e9862c1816ee5d91f084f66a3149df Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 11 May 2016 15:32:26 +0800 Subject: [PATCH 09/83] =?UTF-8?q?=E5=8F=96=E6=B6=88=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 24_day/bootpack.h | 5 ++++- 24_day/console.c | 2 ++ 24_day/timer.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/24_day/bootpack.h b/24_day/bootpack.h index 4215c38..bc14ac9 100644 --- a/24_day/bootpack.h +++ b/24_day/bootpack.h @@ -176,7 +176,8 @@ void sheet_free(struct SHEET *sht); #define MAX_TIMER 500 struct TIMER { struct TIMER *next; - unsigned int timeout, flags; + unsigned int timeout; + char flags, flags2; struct FIFO32 *fifo; int data; }; @@ -192,6 +193,8 @@ void timer_free(struct TIMER *timer); void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data); void timer_settime(struct TIMER *timer, unsigned int timeout); void inthandler20(int *esp); +int timer_cancel(struct TIMER *timer); +void timer_cancelall(struct FIFO32 *fifo); /* mtask.c */ #define MAX_TASKS 1000 /*最大任务数量*/ diff --git a/24_day/console.c b/24_day/console.c index d61d65c..ab3f80a 100644 --- a/24_day/console.c +++ b/24_day/console.c @@ -308,6 +308,7 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) sheet_free(sht); /*关闭*/ } } + timer_cancelall(&task->fifo); memman_free_4k(memman, (int) q, segsiz); } else { cons_putstr0(cons, ".hrb file format error.\n"); @@ -421,6 +422,7 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int } } else if (edx == 16) { reg[7] = (int) timer_alloc(); + ((struct TIMER *) reg[7])->flags2 = 1; /*允许自动取消*/ } else if (edx == 17) { timer_init((struct TIMER *) ebx, &task->fifo, eax + 256); } else if (edx == 18) { diff --git a/24_day/timer.c b/24_day/timer.c index 2c795f8..9018ac8 100644 --- a/24_day/timer.c +++ b/24_day/timer.c @@ -36,6 +36,7 @@ struct TIMER *timer_alloc(void) for (i = 0; i < MAX_TIMER; i++) { if (timerctl.timers0[i].flags == 0) { timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; + timerctl.timers0[i].flags2 = 0; return &timerctl.timers0[i]; } } @@ -116,3 +117,53 @@ void inthandler20(int *esp) } return; } + +int timer_cancel(struct TIMER *timer) +{ + int e; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + if (timer->flags == TIMER_FLAGS_USING) { /*是否需要取消?*/ + if (timer == timerctl.t0) { + /*第一个定时器的取消处理*/ + t = timer->next; + timerctl.t0 = t; + timerctl.next = t->timeout; + } else { + /*非第一个定时器的取消处理*/ + /*找到timer前一个定时器*/ + t = timerctl.t0; + for (;;) { + if (t->next == timer) { + break; + } + t = t->next; + } + t->next = timer->next; + /*将之前“timer的下一个”指向“timer的下一个”*/ + } + timer->flags = TIMER_FLAGS_ALLOC; + io_store_eflags(e); + return 1; /*取消处理成功*/ + } + io_store_eflags(e); + return 0; /*不需要取消处理*/ +} + +void timer_cancelall(struct FIFO32 *fifo) +{ + int e, i; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + for (i = 0; i < MAX_TIMER; i++) { + t = &timerctl.timers0[i]; + if (t->flags != 0 && t->flags2 != 0 && t->fifo == fifo) { + timer_cancel(t); + timer_free(t); + } + } + io_store_eflags(e); + return; +} From 907b8c61ce9817222d4633fbf0e96a99201217fb Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 10:23:23 +0800 Subject: [PATCH 10/83] Add 25 day code --- 25_day/!cons_9x.bat | 1 + 25_day/!cons_nt.bat | 1 + 25_day/Makefile | 220 +++ 25_day/a.c | 8 + 25_day/a_nask.nas | 223 +++ 25_day/asmhead.nas | 202 ++ 25_day/bootpack.c | 371 ++++ 25_day/bootpack.h | 271 +++ 25_day/bug2.c | 3 + 25_day/bug3.c | 9 + 25_day/console.c | 505 +++++ 25_day/dsctbl.c | 60 + 25_day/fifo.c | 63 + 25_day/file.c | 74 + 25_day/graphic.c | 157 ++ 25_day/hankaku.txt | 4609 +++++++++++++++++++++++++++++++++++++++++++ 25_day/hello.nas | 16 + 25_day/hello2.nas | 9 + 25_day/hello3.c | 12 + 25_day/hello4.c | 8 + 25_day/hello5.nas | 20 + 25_day/int.c | 37 + 25_day/ipl10.nas | 109 + 25_day/keyboard.c | 44 + 25_day/lines.c | 29 + 25_day/make.bat | 1 + 25_day/memory.c | 162 ++ 25_day/mouse.c | 76 + 25_day/mtask.c | 201 ++ 25_day/naskfunc.nas | 307 +++ 25_day/noodle.c | 42 + 25_day/sheet.c | 217 ++ 25_day/star1.c | 18 + 25_day/stars.c | 24 + 25_day/stars2.c | 26 + 25_day/timer.c | 169 ++ 25_day/walk.c | 35 + 25_day/window.c | 118 ++ 25_day/winhelo.c | 11 + 25_day/winhelo2.c | 15 + 25_day/winhelo3.c | 19 + 41 files changed, 8502 insertions(+) create mode 100644 25_day/!cons_9x.bat create mode 100644 25_day/!cons_nt.bat create mode 100644 25_day/Makefile create mode 100644 25_day/a.c create mode 100644 25_day/a_nask.nas create mode 100644 25_day/asmhead.nas create mode 100644 25_day/bootpack.c create mode 100644 25_day/bootpack.h create mode 100644 25_day/bug2.c create mode 100644 25_day/bug3.c create mode 100644 25_day/console.c create mode 100644 25_day/dsctbl.c create mode 100644 25_day/fifo.c create mode 100644 25_day/file.c create mode 100644 25_day/graphic.c create mode 100644 25_day/hankaku.txt create mode 100644 25_day/hello.nas create mode 100644 25_day/hello2.nas create mode 100644 25_day/hello3.c create mode 100644 25_day/hello4.c create mode 100644 25_day/hello5.nas create mode 100644 25_day/int.c create mode 100644 25_day/ipl10.nas create mode 100644 25_day/keyboard.c create mode 100644 25_day/lines.c create mode 100644 25_day/make.bat create mode 100644 25_day/memory.c create mode 100644 25_day/mouse.c create mode 100644 25_day/mtask.c create mode 100644 25_day/naskfunc.nas create mode 100644 25_day/noodle.c create mode 100644 25_day/sheet.c create mode 100644 25_day/star1.c create mode 100644 25_day/stars.c create mode 100644 25_day/stars2.c create mode 100644 25_day/timer.c create mode 100644 25_day/walk.c create mode 100644 25_day/window.c create mode 100644 25_day/winhelo.c create mode 100644 25_day/winhelo2.c create mode 100644 25_day/winhelo3.c diff --git a/25_day/!cons_9x.bat b/25_day/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/25_day/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/25_day/!cons_nt.bat b/25_day/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/25_day/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/25_day/Makefile b/25_day/Makefile new file mode 100644 index 0000000..4e81e55 --- /dev/null +++ b/25_day/Makefile @@ -0,0 +1,220 @@ +OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \ + int.obj fifo.obj keyboard.obj mouse.obj memory.obj sheet.obj timer.obj \ + mtask.obj window.obj console.obj file.obj + +TOOLPATH = ../z_tools/ +INCPATH = ../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = $(TOOLPATH)haribote/haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +COPY = copy +DEL = del + +# 默认动作 + +default : + $(MAKE) img + +# 镜像文件生成 + +ipl10.bin : ipl10.nas Makefile + $(NASK) ipl10.nas ipl10.bin ipl10.lst + +asmhead.bin : asmhead.nas Makefile + $(NASK) asmhead.nas asmhead.bin asmhead.lst + +hankaku.bin : hankaku.txt Makefile + $(MAKEFONT) hankaku.txt hankaku.bin + +hankaku.obj : hankaku.bin Makefile + $(BIN2OBJ) hankaku.bin hankaku.obj _hankaku + +bootpack.bim : $(OBJS_BOOTPACK) Makefile + $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \ + $(OBJS_BOOTPACK) +# 3MB+64KB=3136KB + +bootpack.hrb : bootpack.bim Makefile + $(BIM2HRB) bootpack.bim bootpack.hrb 0 + +haribote.sys : asmhead.bin bootpack.hrb Makefile + copy /B asmhead.bin+bootpack.hrb haribote.sys + +hello.hrb : hello.nas Makefile + $(NASK) hello.nas hello.hrb hello.lst + +hello2.hrb : hello2.nas Makefile + $(NASK) hello2.nas hello2.hrb hello2.lst + +a.bim : a.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:a.bim map:a.map a.obj a_nask.obj + +a.hrb : a.bim Makefile + $(BIM2HRB) a.bim a.hrb 0 + +hello3.bim : hello3.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello3.bim map:hello3.map hello3.obj a_nask.obj + +hello3.hrb : hello3.bim Makefile + $(BIM2HRB) hello3.bim hello3.hrb 0 + +hello4.bim : hello4.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello4.bim stack:1k map:hello4.map \ + hello4.obj a_nask.obj + +hello4.hrb : hello4.bim Makefile + $(BIM2HRB) hello4.bim hello4.hrb 0 + +hello5.bim : hello5.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello5.bim stack:1k map:hello5.map hello5.obj + +hello5.hrb : hello5.bim Makefile + $(BIM2HRB) hello5.bim hello5.hrb 0 + +bug2.bim : bug2.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:bug2.bim map:bug2.map bug2.obj + +bug2.hrb : bug2.bim Makefile + $(BIM2HRB) bug2.bim bug2.hrb 0 + +bug3.bim : bug3.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:bug3.bim map:bug3.map bug3.obj a_nask.obj + +bug3.hrb : bug3.bim Makefile + $(BIM2HRB) bug3.bim bug3.hrb 0 + +winhelo.bim : winhelo.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:winhelo.bim stack:1k map:winhelo.map \ + winhelo.obj a_nask.obj + +winhelo.hrb : winhelo.bim Makefile + $(BIM2HRB) winhelo.bim winhelo.hrb 0 + +winhelo2.bim : winhelo2.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:winhelo2.bim stack:1k map:winhelo2.map \ + winhelo2.obj a_nask.obj + +winhelo2.hrb : winhelo2.bim Makefile + $(BIM2HRB) winhelo2.bim winhelo2.hrb 0 + +winhelo3.bim : winhelo3.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:winhelo3.bim stack:1k map:winhelo3.map \ + winhelo3.obj a_nask.obj + +winhelo3.hrb : winhelo3.bim Makefile + $(BIM2HRB) winhelo3.bim winhelo3.hrb 40k + +star1.bim : star1.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:star1.bim stack:1k map:star1.map \ + star1.obj a_nask.obj + +star1.hrb : star1.bim Makefile + $(BIM2HRB) star1.bim star1.hrb 47k + +stars.bim : stars.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:stars.bim stack:1k map:stars.map \ + stars.obj a_nask.obj + +stars.hrb : stars.bim Makefile + $(BIM2HRB) stars.bim stars.hrb 47k + +stars2.bim : stars2.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:stars2.bim stack:1k map:stars2.map \ + stars2.obj a_nask.obj + +stars2.hrb : stars2.bim Makefile + $(BIM2HRB) stars2.bim stars2.hrb 47k + +lines.bim : lines.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:lines.bim stack:1k map:lines.map \ + lines.obj a_nask.obj + +lines.hrb : lines.bim Makefile + $(BIM2HRB) lines.bim lines.hrb 48k + +walk.bim : walk.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:walk.bim stack:1k map:walk.map \ + walk.obj a_nask.obj + +walk.hrb : walk.bim Makefile + $(BIM2HRB) walk.bim walk.hrb 48k + +noodle.bim : noodle.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:noodle.bim stack:1k map:noodle.map \ + noodle.obj a_nask.obj + +noodle.hrb : noodle.bim Makefile + $(BIM2HRB) noodle.bim noodle.hrb 40k + +haribote.img : ipl10.bin haribote.sys Makefile \ + hello.hrb hello2.hrb a.hrb hello3.hrb hello4.hrb hello5.hrb \ + winhelo.hrb winhelo2.hrb winhelo3.hrb star1.hrb stars.hrb stars2.hrb \ + lines.hrb walk.hrb noodle.hrb + $(EDIMG) imgin:../z_tools/fdimg0at.tek \ + wbinimg src:ipl10.bin len:512 from:0 to:0 \ + copy from:haribote.sys to:@: \ + copy from:ipl10.nas to:@: \ + copy from:make.bat to:@: \ + copy from:hello.hrb to:@: \ + copy from:hello2.hrb to:@: \ + copy from:a.hrb to:@: \ + copy from:hello3.hrb to:@: \ + copy from:hello4.hrb to:@: \ + copy from:hello5.hrb to:@: \ + copy from:winhelo.hrb to:@: \ + copy from:winhelo2.hrb to:@: \ + copy from:winhelo3.hrb to:@: \ + copy from:star1.hrb to:@: \ + copy from:stars.hrb to:@: \ + copy from:stars2.hrb to:@: \ + copy from:lines.hrb to:@: \ + copy from:walk.hrb to:@: \ + copy from:noodle.hrb to:@: \ + imgout:haribote.img + +# 其他指令 + +%.gas : %.c bootpack.h Makefile + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +# 运行程序 + +img : + $(MAKE) haribote.img + +run : + $(MAKE) img + $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../z_tools/qemu + +install : + $(MAKE) img + $(IMGTOL) w a: haribote.img + +clean : + -$(DEL) *.bin + -$(DEL) *.lst + -$(DEL) *.obj + -$(DEL) bootpack.map + -$(DEL) bootpack.bim + -$(DEL) bootpack.hrb + -$(DEL) haribote.sys + +src_only : + $(MAKE) clean + -$(DEL) haribote.img diff --git a/25_day/a.c b/25_day/a.c new file mode 100644 index 0000000..a6668af --- /dev/null +++ b/25_day/a.c @@ -0,0 +1,8 @@ +void api_putchar(int c); +void api_end(void); + +void HariMain(void) +{ + api_putchar('A'); + api_end(); +} diff --git a/25_day/a_nask.nas b/25_day/a_nask.nas new file mode 100644 index 0000000..56fe642 --- /dev/null +++ b/25_day/a_nask.nas @@ -0,0 +1,223 @@ +[FORMAT "WCOFF"] ; 生成对象文件的模式 +[INSTRSET "i486p"] ; 表示使用486兼容指令集 +[BITS 32] ; 生成32位模式机器语言 +[FILE "a_nask.nas"] ; 源文件名信息 + + GLOBAL _api_putchar + GLOBAL _api_putstr0 + GLOBAL _api_end + GLOBAL _api_openwin + GLOBAL _api_putstrwin + GLOBAL _api_boxfilwin + GLOBAL _api_initmalloc + GLOBAL _api_malloc + GLOBAL _api_free + GLOBAL _api_point + GLOBAL _api_refreshwin + GLOBAL _api_linewin + GLOBAL _api_closewin + GLOBAL _api_getkey + GLOBAL _api_alloctimer + GLOBAL _api_inittimer + GLOBAL _api_settimer + GLOBAL _api_freetimer + +[SECTION .text] + +_api_putchar: ; void api_putchar(int c); + MOV EDX,1 + MOV AL,[ESP+4] ; c + INT 0x40 + RET + +_api_putstr0: ; void api_putstr0(char *s); + PUSH EBX + MOV EDX,2 + MOV EBX,[ESP+8] ; s + INT 0x40 + POP EBX + RET + +_api_end: ; void api_end(void); + MOV EDX,4 + INT 0x40 + +_api_openwin: ; int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,5 + MOV EBX,[ESP+16] ; buf + MOV ESI,[ESP+20] ; xsiz + MOV EDI,[ESP+24] ; ysiz + MOV EAX,[ESP+28] ; col_inv + MOV ECX,[ESP+32] ; title + INT 0x40 + POP EBX + POP ESI + POP EDI + RET + +_api_putstrwin: ; void api_putstrwin(int win, int x, int y, int col, int len, char *str); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,6 + MOV EBX,[ESP+20] ; win + MOV ESI,[ESP+24] ; x + MOV EDI,[ESP+28] ; y + MOV EAX,[ESP+32] ; col + MOV ECX,[ESP+36] ; len + MOV EBP,[ESP+40] ; str + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET + +_api_boxfilwin: ; void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,7 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET + +_api_initmalloc: ; void api_initmalloc(void); + PUSH EBX + MOV EDX,8 + MOV EBX,[CS:0x0020] ; malloc内存空间的地址 + MOV EAX,EBX + ADD EAX,32*1024 ; 加上32KB + MOV ECX,[CS:0x0000] ; 数据段的大小 + SUB ECX,EAX + INT 0x40 + POP EBX + RET + +_api_malloc: ; char *api_malloc(int size); + PUSH EBX + MOV EDX,9 + MOV EBX,[CS:0x0020] + MOV ECX,[ESP+8] ; size + INT 0x40 + POP EBX + RET + +_api_free: ; void api_free(char *addr, int size); + PUSH EBX + MOV EDX,10 + MOV EBX,[CS:0x0020] + MOV EAX,[ESP+ 8] ; addr + MOV ECX,[ESP+12] ; size + INT 0x40 + POP EBX + RET + +_api_point: ; void api_point(int win, int x, int y, int col); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,11 + MOV EBX,[ESP+16] ; win + MOV ESI,[ESP+20] ; x + MOV EDI,[ESP+24] ; y + MOV EAX,[ESP+28] ; col + INT 0x40 + POP EBX + POP ESI + POP EDI + RET + +_api_refreshwin: ; void api_refreshwin(int win, int x0, int y0, int x1, int y1); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,12 + MOV EBX,[ESP+16] ; win + MOV EAX,[ESP+20] ; x0 + MOV ECX,[ESP+24] ; y0 + MOV ESI,[ESP+28] ; x1 + MOV EDI,[ESP+32] ; y1 + INT 0x40 + POP EBX + POP ESI + POP EDI + RET + +_api_linewin: ; void api_linewin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,13 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET + +_api_closewin: ; void api_closewin(int win); + PUSH EBX + MOV EDX,14 + MOV EBX,[ESP+8] ; win + INT 0x40 + POP EBX + RET + +_api_getkey: ; int api_getkey(int mode); + MOV EDX,15 + MOV EAX,[ESP+4] ; mode + INT 0x40 + RET + +_api_alloctimer: ; int api_alloctimer(void); + MOV EDX,16 + INT 0x40 + RET + +_api_inittimer: ; void api_inittimer(int timer, int data); + PUSH EBX + MOV EDX,17 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; data + INT 0x40 + POP EBX + RET + +_api_settimer: ; void api_settimer(int timer, int time); + PUSH EBX + MOV EDX,18 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; time + INT 0x40 + POP EBX + RET + +_api_freetimer: ; void api_freetimer(int timer); + PUSH EBX + MOV EDX,19 + MOV EBX,[ESP+ 8] ; timer + INT 0x40 + POP EBX + RET diff --git a/25_day/asmhead.nas b/25_day/asmhead.nas new file mode 100644 index 0000000..ad35d76 --- /dev/null +++ b/25_day/asmhead.nas @@ -0,0 +1,202 @@ +; haribote-os boot asm +; TAB=4 + +[INSTRSET "i486p"] + +VBEMODE EQU 0x105 ; 1024 x 768 x 8bit 彩色 +; 显示模式 +; 0x100 : 640 x 400 x 8bit 彩色 +; 0x101 : 640 x 480 x 8bit 彩色 +; 0x103 : 800 x 600 x 8bit 彩色 +; 0x105 : 1024 x 768 x 8bit 彩色 +; 0x107 : 1280 x 1024 x 8bit 彩色 + +BOTPAK EQU 0x00280000 ; 加载bootpack +DSKCAC EQU 0x00100000 ; 磁盘缓存的位置 +DSKCAC0 EQU 0x00008000 ; 磁盘缓存的位置(实模式) + +; BOOT_INFO 相关 +CYLS EQU 0x0ff0 ; 引导扇区设置 +LEDS EQU 0x0ff1 +VMODE EQU 0x0ff2 ; 关于颜色的信息 +SCRNX EQU 0x0ff4 ; 分辨率X +SCRNY EQU 0x0ff6 ; 分辨率Y +VRAM EQU 0x0ff8 ; 图像缓冲区的起始地址 + + ORG 0xc200 ; 这个的程序要被装载的内存地址 + +; 确认VBE是否存在 + + MOV AX,0x9000 + MOV ES,AX + MOV DI,0 + MOV AX,0x4f00 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 检查VBE的版本 + + MOV AX,[ES:DI+4] + CMP AX,0x0200 + JB scrn320 ; if (AX < 0x0200) goto scrn320 + +; 取得画面模式信息 + + MOV CX,VBEMODE + MOV AX,0x4f01 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 画面模式信息的确认 + CMP BYTE [ES:DI+0x19],8 ;颜色数必须为8 + JNE scrn320 + CMP BYTE [ES:DI+0x1b],4 ;颜色的指定方法必须为4(4是调色板模式) + JNE scrn320 + MOV AX,[ES:DI+0x00] ;模式属性bit7不是1就不能加上0x4000 + AND AX,0x0080 + JZ scrn320 ; 模式属性的bit7是0,所以放弃 + +; 画面设置 + + MOV BX,VBEMODE+0x4000 + MOV AX,0x4f02 + INT 0x10 + MOV BYTE [VMODE],8 ; 屏幕的模式(参考C语言的引用) + MOV AX,[ES:DI+0x12] + MOV [SCRNX],AX + MOV AX,[ES:DI+0x14] + MOV [SCRNY],AX + MOV EAX,[ES:DI+0x28] ;VRAM的地址 + MOV [VRAM],EAX + JMP keystatus + +scrn320: + MOV AL,0x13 ; VGA图、320x200x8bit彩色 + MOV AH,0x00 + INT 0x10 + MOV BYTE [VMODE],8 ; 记下画面模式(参考C语言) + MOV WORD [SCRNX],320 + MOV WORD [SCRNY],200 + MOV DWORD [VRAM],0x000a0000 + +; 通过 BIOS 获取指示灯状态 + +keystatus: + MOV AH,0x02 + INT 0x16 ; keyboard BIOS + MOV [LEDS],AL + +; PIC关闭一切中断 +; 根据AT兼容机的规格,如果要初始化PIC, +; 必须在CLI之前进行,否则有时会挂起。 +; 随后进行PIC的初始化。 + + MOV AL,0xff + OUT 0x21,AL + NOP ; 如果连续执行OUT指令,有些机种会无法正常运行 + OUT 0xa1,AL + + CLI ; 禁止CPU级别的中断 + +; 为了让CPU能够访问1MB以上的内存空间,设定A20GATE + + CALL waitkbdout + MOV AL,0xd1 + OUT 0x64,AL + CALL waitkbdout + MOV AL,0xdf ; enable A20 + OUT 0x60,AL + CALL waitkbdout + +; 切换到保护模式 + +[INSTRSET "i486p"] ; 说明使用486指令 + + LGDT [GDTR0] ; 设置临时GDT + MOV EAX,CR0 + AND EAX,0x7fffffff ; 设bit31为0(禁用分页) + OR EAX,0x00000001 ; bit0到1转换(保护模式过渡) + MOV CR0,EAX + JMP pipelineflush +pipelineflush: + MOV AX,1*8 ; 可读写的段 32bit + MOV DS,AX + MOV ES,AX + MOV FS,AX + MOV GS,AX + MOV SS,AX + +; bootpack传递 + + MOV ESI,bootpack ; 转送源 + MOV EDI,BOTPAK ; 转送目标 + MOV ECX,512*1024/4 + CALL memcpy + +; 磁盘数据最终转送到它本来的位置去 +; 首先从启动扇区开始 + + MOV ESI,0x7c00 ; 转送源 + MOV EDI,DSKCAC ; 转送目标 + MOV ECX,512/4 + CALL memcpy + +; 剩余的全部 + + MOV ESI,DSKCAC0+512 ; 转送源 + MOV EDI,DSKCAC+512 ; 转送源目标 + MOV ECX,0 + MOV CL,BYTE [CYLS] + IMUL ECX,512*18*2/4 ; 从柱面数变换为字节数/4 + SUB ECX,512/4 ; 减去 IPL 偏移量 + CALL memcpy + +; 必须由asmhead来完成的工作,至此全部完毕 +; 以后就交由bootpack来完成 + +; bootpack启动 + + MOV EBX,BOTPAK + MOV ECX,[EBX+16] + ADD ECX,3 ; ECX += 3; + SHR ECX,2 ; ECX /= 4; + JZ skip ; 没有要转送的东西时 + MOV ESI,[EBX+20] ; 转送源 + ADD ESI,EBX + MOV EDI,[EBX+12] ; 转送目标 + CALL memcpy +skip: + MOV ESP,[EBX+12] ; 堆栈的初始化 + JMP DWORD 2*8:0x0000001b + +waitkbdout: + IN AL,0x64 + AND AL,0x02 + JNZ waitkbdout ; AND的结果如果不是0,就跳到waitkbdout + RET + +memcpy: + MOV EAX,[ESI] + ADD ESI,4 + MOV [EDI],EAX + ADD EDI,4 + SUB ECX,1 + JNZ memcpy ; 减法运算的结果如果不是0,就跳转到memcpy + RET +; memcpy地址前缀大小 + + ALIGNB 16 +GDT0: + RESB 8 ; 初始值 + DW 0xffff,0x0000,0x9200,0x00cf ; 可以读写的段(segment)32bit + DW 0xffff,0x0000,0x9a28,0x0047 ; 可执行的文件的32bit寄存器(bootpack用) + + DW 0 +GDTR0: + DW 8*3-1 + DD GDT0 + + ALIGNB 16 +bootpack: diff --git a/25_day/bootpack.c b/25_day/bootpack.c new file mode 100644 index 0000000..0bff4b5 --- /dev/null +++ b/25_day/bootpack.c @@ -0,0 +1,371 @@ +/* bootpack */ + +#include "bootpack.h" +#include + +#define KEYCMD_LED 0xed + +int keywin_off(struct SHEET *key_win, struct SHEET *sht_win, int cur_c, int cur_x); +int keywin_on(struct SHEET *key_win, struct SHEET *sht_win, int cur_c); + +void HariMain(void) +{ + struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; + struct SHTCTL *shtctl; + char s[40]; + struct FIFO32 fifo, keycmd; + int fifobuf[128], keycmd_buf[32]; + int mx, my, i, cursor_x, cursor_c; + unsigned int memtotal; + struct MOUSE_DEC mdec; + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + unsigned char *buf_back, buf_mouse[256], *buf_win, *buf_cons; + struct SHEET *sht_back, *sht_mouse, *sht_win, *sht_cons; + struct TASK *task_a, *task_cons; + struct TIMER *timer; + static char keytable0[0x80] = { + 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0 + }; + static char keytable1[0x80] = { + 0, 0, '!', 0x22, '#', '$', '%', '&', 0x27, '(', ')', '~', '=', '~', 0, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', '+', '*', 0, 0, '}', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, '|', 0, 0 + }; + int key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; + struct CONSOLE *cons; + int j, x, y, mmx = -1, mmy = -1; + struct SHEET *sht = 0, *key_win; + + init_gdtidt(); + init_pic(); + io_sti(); /* IDT/PIC的初始化已经完成,于是开放CPU的中断 */ + fifo32_init(&fifo, 128, fifobuf, 0); + init_pit(); + init_keyboard(&fifo, 256); + enable_mouse(&fifo, 512, &mdec); + io_out8(PIC0_IMR, 0xf8); /* 设定PIT和PIC1以及键盘为许可(11111000) */ + io_out8(PIC1_IMR, 0xef); /* 开放鼠标中断(11101111) */ + fifo32_init(&keycmd, 32, keycmd_buf, 0); + + memtotal = memtest(0x00400000, 0xbfffffff); + memman_init(memman); + memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */ + memman_free(memman, 0x00400000, memtotal - 0x00400000); + + init_palette(); + shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny); + task_a = task_init(memman); + fifo.task = task_a; + task_run(task_a, 1, 2); + *((int *) 0x0fe4) = (int) shtctl; + + /* sht_back */ + sht_back = sheet_alloc(shtctl); + buf_back = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny); + sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 无透明色 */ + init_screen8(buf_back, binfo->scrnx, binfo->scrny); + + /* sht_cons */ + sht_cons = sheet_alloc(shtctl); + buf_cons = (unsigned char *) memman_alloc_4k(memman, 256 * 165); + sheet_setbuf(sht_cons, buf_cons, 256, 165, -1); /* 无透明色 */ + make_window8(buf_cons, 256, 165, "console", 0); + make_textbox8(sht_cons, 8, 28, 240, 128, COL8_000000); + task_cons = task_alloc(); + task_cons->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 12; + task_cons->tss.eip = (int) &console_task; + task_cons->tss.es = 1 * 8; + task_cons->tss.cs = 2 * 8; + task_cons->tss.ss = 1 * 8; + task_cons->tss.ds = 1 * 8; + task_cons->tss.fs = 1 * 8; + task_cons->tss.gs = 1 * 8; + *((int *) (task_cons->tss.esp + 4)) = (int) sht_cons; + *((int *) (task_cons->tss.esp + 8)) = memtotal; + task_run(task_cons, 2, 2); /* level=2, priority=2 */ + + /* sht_win */ + sht_win = sheet_alloc(shtctl); + buf_win = (unsigned char *) memman_alloc_4k(memman, 160 * 52); + sheet_setbuf(sht_win, buf_win, 144, 52, -1); /* 无透明色 */ + make_window8(buf_win, 144, 52, "task_a", 1); + make_textbox8(sht_win, 8, 28, 128, 16, COL8_FFFFFF); + cursor_x = 8; + cursor_c = COL8_FFFFFF; + timer = timer_alloc(); + timer_init(timer, &fifo, 1); + timer_settime(timer, 50); + + /* sht_mouse */ + sht_mouse = sheet_alloc(shtctl); + sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99); + init_mouse_cursor8(buf_mouse, 99); + mx = (binfo->scrnx - 16) / 2; /* 计算坐标使其位于画面中央 */ + my = (binfo->scrny - 28 - 16) / 2; + + sheet_slide(sht_back, 0, 0); + sheet_slide(sht_cons, 32, 4); + sheet_slide(sht_win, 64, 56); + sheet_slide(sht_mouse, mx, my); + sheet_updown(sht_back, 0); + sheet_updown(sht_cons, 1); + sheet_updown(sht_win, 2); + sheet_updown(sht_mouse, 3); + key_win = sht_win; + sht_cons->task = task_cons; + sht_cons->flags |= 0x20; /*有光标*/ + + /*为了避免和键盘当前状态冲突,在一开始先进行设置*/ + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + + for (;;) { + if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0) { + /*如果存在向键盘控制器发送的数据,则发送它 */ + keycmd_wait = fifo32_get(&keycmd); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + io_cli(); + if (fifo32_status(&fifo) == 0) { + task_sleep(task_a); + io_sti(); + } else { + i = fifo32_get(&fifo); + io_sti(); + if (key_win->flags == 0) { /*输入窗口被关闭*/ + key_win = shtctl->sheets[shtctl->top - 1]; + cursor_c = keywin_on(key_win, sht_win, cursor_c); + } + if (256 <= i && i <= 511) { /* 键盘数据*/ + if (i < 0x80 + 256) { /*将按键编码转换为字符编码*/ + if (key_shift == 0) { + s[0] = keytable0[i - 256]; + } else { + s[0] = keytable1[i - 256]; + } + } else { + s[0] = 0; + } + if ('A' <= s[0] && s[0] <= 'Z') { /*当输入字符为英文字母时*/ + if (((key_leds & 4) == 0 && key_shift == 0) ||((key_leds & 4) != 0 && key_shift != 0)) { + s[0] += 0x20; /*将大写字母转换为小写字母*/ + } + } + if (s[0] != 0) { /*一般字符*/ + if (key_win == sht_win) { /*发送给任务A */ + if (cursor_x < 128) { + /*显示一个字符之后将光标后移一位*/ + s[1] = 0; + putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1); + cursor_x += 8; + } + } else { /*发送给命令行窗口*/ + fifo32_put(&key_win->task->fifo, s[0] + 256); + } + } + if (i == 256 + 0x0e) { /* 退格键 */ + if (key_win == sht_win) { /*发送给任务A */ + if (cursor_x > 8) { + /*用空白擦除光标后将光标前移一位*/ + putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1); + cursor_x -= 8; + } + } else { /*发送给命令行窗口*/ + fifo32_put(&key_win->task->fifo, 8 + 256); + } + } + if (i == 256 + 0x1c) { /*回车键*/ + if (key_win != sht_win) { /*发送至命令行窗口*/ + fifo32_put(&key_win->task->fifo, 10 + 256); + } + } + if (i == 256 + 0x0f) { /* Tab键 */ + cursor_c = keywin_off(key_win, sht_win, cursor_c, cursor_x); + j = key_win->height - 1; + if (j == 0) { + j = shtctl->top - 1; + } + key_win = shtctl->sheets[j]; + cursor_c = keywin_on(key_win, sht_win, cursor_c); + } + if (i == 256 + 0x2a) { /*左Shift ON */ + key_shift |= 1; + } + if (i == 256 + 0x36) { /*右Shift ON */ + key_shift |= 2; + } + if (i == 256 + 0xaa) { /*左Shift OFF */ + key_shift &= ~1; + } + if (i == 256 + 0xb6) { /*右Shift OFF */ + key_shift &= ~2; + } + if (i == 256 + 0x3a) { /* CapsLock */ + key_leds ^= 4; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x45) { /* NumLock */ + key_leds ^= 2; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x46) { /* ScrollLock */ + key_leds ^= 1; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x3b && key_shift != 0 && task_cons->tss.ss0 != 0) { /* Shift+F1 */ + cons = (struct CONSOLE *) *((int *) 0x0fec); + cons_putstr0(cons, "\nBreak(key) :\n"); + io_cli(); /*不能在改变寄存器值时切换到其他任务*/ + task_cons->tss.eax = (int) &(task_cons->tss.esp0); + task_cons->tss.eip = (int) asm_end_app; + io_sti(); + } + if (i == 256 + 0x57 && shtctl->top > 2) { /* F11 */ + sheet_updown(shtctl->sheets[1], shtctl->top - 1); + } + if (i == 256 + 0xfa) { /*键盘成功接收到数据*/ + keycmd_wait = -1; + } + if (i == 256 + 0xfe) { /*键盘没有成功接收到数据*/ + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + /*重新显示光标*/ + if (cursor_c >= 0) { + boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); + } + sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44); + } else if (512 <= i && i <= 767) { /* 鼠标数据*/ + if (mouse_decode(&mdec, i - 512) != 0) { + /* 已经收集了3字节的数据,移动光标 */ + mx += mdec.x; + my += mdec.y; + if (mx < 0) { + mx = 0; + } + if (my < 0) { + my = 0; + } + if (mx > binfo->scrnx - 1) { + mx = binfo->scrnx - 1; + } + if (my > binfo->scrny - 1) { + my = binfo->scrny - 1; + } + + sheet_slide(sht_mouse, mx, my);/* 包含sheet_refresh含sheet_refresh */ + + if ((mdec.btn & 0x01) != 0) { /* 按下左键 */ + if (mmx < 0) { + /*如果处于通常模式*/ + /*按照从上到下的顺序寻找鼠标所指向的图层*/ + for (j = shtctl->top - 1; j > 0; j--) { + sht = shtctl->sheets[j]; + x = mx - sht->vx0; + y = my - sht->vy0; + if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) { + if (sht->buf[y * sht->bxsize + x] != sht->col_inv) { + sheet_updown(sht, shtctl->top - 1); + if (sht != key_win) { + cursor_c = keywin_off(key_win, sht_win, cursor_c, cursor_x); + key_win = sht; + cursor_c = keywin_on(key_win, sht_win, cursor_c);/*到此结束*/ + } + if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) { + mmx = mx; /*进入窗口移动模式*/ + mmy = my; + } + if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <=y && y < 19) { + /*点击“×”按钮*/ + if ((sht->flags & 0x10) != 0) { /*该窗口是否为应用程序窗口?*/ + cons = (struct CONSOLE *) *((int *) 0x0fec); + cons_putstr0(cons, "\nBreak(mouse) :\n"); + io_cli(); /*强制结束处理中禁止切换任务*/ + task_cons->tss.eax = (int) + &(task_cons->tss.esp0); + task_cons->tss.eip = (int) asm_end_app; + io_sti(); + } + } + break; + } + } + } + } else { + /*如果处于窗口移动模式*/ + x = mx - mmx; /*计算鼠标的移动距离*/ + y = my - mmy; + sheet_slide(sht, sht->vx0 + x, sht->vy0 + y); + mmx = mx; /*更新为移动后的坐标*/ + mmy = my; + } + } else { + /*没有按下左键*/ + mmx = -1; /*返回通常模式*/ + } + + } + } else if (i <= 1) { /* 光标用定时器*/ + if (i != 0) { + timer_init(timer, &fifo, 0); /* 下面设定0 */ + if (cursor_c >= 0) { + cursor_c = COL8_000000; + } + } else { + timer_init(timer, &fifo, 1); /* 下面设定1 */ + if (cursor_c >= 0) { + cursor_c = COL8_FFFFFF; + } + } + timer_settime(timer, 50); + if (cursor_c >= 0) { + boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); + sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44); + } + } + } + } +} + +int keywin_off(struct SHEET *key_win, struct SHEET *sht_win, int cur_c, int cur_x) +{ + change_wtitle8(key_win, 0); + if (key_win == sht_win) { + cur_c = -1; /*删除光标*/ + boxfill8(sht_win->buf, sht_win->bxsize, COL8_FFFFFF, cur_x, 28, cur_x + 7, 43); + } else { + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 3); /*命令行窗口光标OFF */ + } + } + return cur_c; +} + +int keywin_on(struct SHEET *key_win, struct SHEET *sht_win, int cur_c) +{ + change_wtitle8(key_win, 1); + if (key_win == sht_win) { + cur_c = COL8_000000; /*显示光标*/ + } else { + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 2); /*命令行窗口光标ON */ + } + } + return cur_c; +} diff --git a/25_day/bootpack.h b/25_day/bootpack.h new file mode 100644 index 0000000..bc14ac9 --- /dev/null +++ b/25_day/bootpack.h @@ -0,0 +1,271 @@ +/* asmhead.nas */ +struct BOOTINFO { /* 0x0ff0-0x0fff */ + char cyls; /* 启动区读磁盘读到此为止 */ + char leds; /* 启动时键盘的LED的状态 */ + char vmode; /* 显卡模式为多少位彩色 */ + char reserve; + short scrnx, scrny; /* 画面分辨率 */ + char *vram; +}; +#define ADR_BOOTINFO 0x00000ff0 +#define ADR_DISKIMG 0x00100000 + +/* naskfunc.nas */ +void io_hlt(void); +void io_cli(void); +void io_sti(void); +void io_stihlt(void); +int io_in8(int port); +void io_out8(int port, int data); +int io_load_eflags(void); +void io_store_eflags(int eflags); +void load_gdtr(int limit, int addr); +void load_idtr(int limit, int addr); +int load_cr0(void); +void store_cr0(int cr0); +void load_tr(int tr); +void asm_inthandler0c(void); +void asm_inthandler0d(void); +void asm_inthandler20(void); +void asm_inthandler21(void); +void asm_inthandler27(void); +void asm_inthandler2c(void); +unsigned int memtest_sub(unsigned int start, unsigned int end); +void farjmp(int eip, int cs); +void farcall(int eip, int cs); +void asm_hrb_api(void); +void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); +void asm_end_app(void); + +/* fifo.c */ +struct FIFO32 { + int *buf; + int p, q, size, free, flags; + struct TASK *task; +}; +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task); +int fifo32_put(struct FIFO32 *fifo, int data); +int fifo32_get(struct FIFO32 *fifo); +int fifo32_status(struct FIFO32 *fifo); + +/* graphic.c */ +void init_palette(void); +void set_palette(int start, int end, unsigned char *rgb); +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); +void init_screen8(char *vram, int x, int y); +void putfont8(char *vram, int xsize, int x, int y, char c, char *font); +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s); +void init_mouse_cursor8(char *mouse, char bc); +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize); +#define COL8_000000 0 +#define COL8_FF0000 1 +#define COL8_00FF00 2 +#define COL8_FFFF00 3 +#define COL8_0000FF 4 +#define COL8_FF00FF 5 +#define COL8_00FFFF 6 +#define COL8_FFFFFF 7 +#define COL8_C6C6C6 8 +#define COL8_840000 9 +#define COL8_008400 10 +#define COL8_848400 11 +#define COL8_000084 12 +#define COL8_840084 13 +#define COL8_008484 14 +#define COL8_848484 15 + +/* dsctbl.c */ +struct SEGMENT_DESCRIPTOR { + short limit_low, base_low; + char base_mid, access_right; + char limit_high, base_high; +}; +struct GATE_DESCRIPTOR { + short offset_low, selector; + char dw_count, access_right; + short offset_high; +}; +void init_gdtidt(void); +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar); +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar); +#define ADR_IDT 0x0026f800 +#define LIMIT_IDT 0x000007ff +#define ADR_GDT 0x00270000 +#define LIMIT_GDT 0x0000ffff +#define ADR_BOTPAK 0x00280000 +#define LIMIT_BOTPAK 0x0007ffff +#define AR_DATA32_RW 0x4092 +#define AR_CODE32_ER 0x409a +#define AR_TSS32 0x0089 +#define AR_INTGATE32 0x008e + +/* int.c */ +void init_pic(void); +void inthandler27(int *esp); +#define PIC0_ICW1 0x0020 +#define PIC0_OCW2 0x0020 +#define PIC0_IMR 0x0021 +#define PIC0_ICW2 0x0021 +#define PIC0_ICW3 0x0021 +#define PIC0_ICW4 0x0021 +#define PIC1_ICW1 0x00a0 +#define PIC1_OCW2 0x00a0 +#define PIC1_IMR 0x00a1 +#define PIC1_ICW2 0x00a1 +#define PIC1_ICW3 0x00a1 +#define PIC1_ICW4 0x00a1 + +/* keyboard.c */ +void inthandler21(int *esp); +void wait_KBC_sendready(void); +void init_keyboard(struct FIFO32 *fifo, int data0); +#define PORT_KEYDAT 0x0060 +#define PORT_KEYCMD 0x0064 + +/* mouse.c */ +struct MOUSE_DEC { + unsigned char buf[3], phase; + int x, y, btn; +}; +void inthandler2c(int *esp); +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec); +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat); + +/* memory.c */ +#define MEMMAN_FREES 4090 /* 大约是32KB*/ +#define MEMMAN_ADDR 0x003c0000 +struct FREEINFO { /* 可用信息 */ + unsigned int addr, size; +}; +struct MEMMAN { /* 内存管理 */ + int frees, maxfrees, lostsize, losts; + struct FREEINFO free[MEMMAN_FREES]; +}; +unsigned int memtest(unsigned int start, unsigned int end); +void memman_init(struct MEMMAN *man); +unsigned int memman_total(struct MEMMAN *man); +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size); +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size); +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size); +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size); + +/* sheet.c */ +#define MAX_SHEETS 256 +struct SHEET { + unsigned char *buf; + int bxsize, bysize, vx0, vy0, col_inv, height, flags; + struct SHTCTL *ctl; + struct TASK *task; +}; +struct SHTCTL { + unsigned char *vram, *map; + int xsize, ysize, top; + struct SHEET *sheets[MAX_SHEETS]; + struct SHEET sheets0[MAX_SHEETS]; +}; +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize); +struct SHEET *sheet_alloc(struct SHTCTL *ctl); +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv); +void sheet_updown(struct SHEET *sht, int height); +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1); +void sheet_slide(struct SHEET *sht, int vx0, int vy0); +void sheet_free(struct SHEET *sht); + +/* timer.c */ +#define MAX_TIMER 500 +struct TIMER { + struct TIMER *next; + unsigned int timeout; + char flags, flags2; + struct FIFO32 *fifo; + int data; +}; +struct TIMERCTL { + unsigned int count, next; + struct TIMER *t0; + struct TIMER timers0[MAX_TIMER]; +}; +extern struct TIMERCTL timerctl; +void init_pit(void); +struct TIMER *timer_alloc(void); +void timer_free(struct TIMER *timer); +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data); +void timer_settime(struct TIMER *timer, unsigned int timeout); +void inthandler20(int *esp); +int timer_cancel(struct TIMER *timer); +void timer_cancelall(struct FIFO32 *fifo); + +/* mtask.c */ +#define MAX_TASKS 1000 /*最大任务数量*/ +#define TASK_GDT0 3 /*定义从GDT的几号开始分配给TSS */ +#define MAX_TASKS_LV 100 +#define MAX_TASKLEVELS 10 +struct TSS32 { + int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3; + int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi; + int es, cs, ss, ds, fs, gs; + int ldtr, iomap; +}; +struct TASK { + int sel, flags; /* sel用来存放GDT的编号*/ + int level, priority; /* 优先级 */ + struct FIFO32 fifo; + struct TSS32 tss; +}; +struct TASKLEVEL { + int running; /*正在运行的任务数量*/ + int now; /*这个变量用来记录当前正在运行的是哪个任务*/ + struct TASK *tasks[MAX_TASKS_LV]; +}; +struct TASKCTL { + int now_lv; /*现在活动中的LEVEL */ + char lv_change; /*在下次任务切换时是否需要改变LEVEL */ + struct TASKLEVEL level[MAX_TASKLEVELS]; + struct TASK tasks0[MAX_TASKS]; +}; +extern struct TIMER *task_timer; +struct TASK *task_init(struct MEMMAN *memman); +struct TASK *task_alloc(void); +void task_run(struct TASK *task, int level, int priority); +void task_switch(void); +void task_sleep(struct TASK *task); + +/* window.c */ +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act); +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l); +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c); +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act); +void change_wtitle8(struct SHEET *sht, char act); + +/* console.c */ +struct CONSOLE { + struct SHEET *sht; + int cur_x, cur_y, cur_c; + struct TIMER *timer; +}; +void console_task(struct SHEET *sheet, unsigned int memtotal); +void cons_putchar(struct CONSOLE *cons, int chr, char move); +void cons_newline(struct CONSOLE *cons); +void cons_putstr0(struct CONSOLE *cons, char *s); +void cons_putstr1(struct CONSOLE *cons, char *s, int l); +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, unsigned int memtotal); +void cmd_mem(struct CONSOLE *cons, unsigned int memtotal); +void cmd_cls(struct CONSOLE *cons); +void cmd_dir(struct CONSOLE *cons); +void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline); +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline); +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax); +int *inthandler0c(int *esp); +int *inthandler0d(int *esp); + +/* file.c */ +struct FILEINFO { + unsigned char name[8], ext[3], type; + char reserve[10]; + unsigned short time, date, clustno; + unsigned int size; +}; +void file_readfat(int *fat, unsigned char *img); +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img); +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max); diff --git a/25_day/bug2.c b/25_day/bug2.c new file mode 100644 index 0000000..c6f65e7 --- /dev/null +++ b/25_day/bug2.c @@ -0,0 +1,3 @@ +void HariMain(void){ + for (;;) { } +} \ No newline at end of file diff --git a/25_day/bug3.c b/25_day/bug3.c new file mode 100644 index 0000000..5982e10 --- /dev/null +++ b/25_day/bug3.c @@ -0,0 +1,9 @@ +void api_putchar(int c); +void api_end(void); + +void HariMain(void) +{ + for (;;) { + api_putchar('a'); + } +} diff --git a/25_day/console.c b/25_day/console.c new file mode 100644 index 0000000..ab3f80a --- /dev/null +++ b/25_day/console.c @@ -0,0 +1,505 @@ +/* 命令行窗口相关 */ + +#include "bootpack.h" +#include +#include + +void console_task(struct SHEET *sheet, unsigned int memtotal) +{ + struct TIMER *timer; + struct TASK *task = task_now(); + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + int i, fifobuf[128], *fat = (int *) memman_alloc_4k(memman, 4 * 2880); + struct CONSOLE cons; + char cmdline[30]; + cons.sht = sheet; + cons.cur_x = 8; + cons.cur_y = 28; + cons.cur_c = -1; + *((int *) 0x0fec) = (int) &cons; + + fifo32_init(&task->fifo, 128, fifobuf, task); + timer = timer_alloc(); + timer_init(timer, &task->fifo, 1); + timer_settime(timer, 50); + file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); + + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + task_sleep(task); + io_sti(); + } else { + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1) { /*光标用定时器*/ + if (i != 0) { + timer_init(timer, &task->fifo, 0); /*下次置0 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_FFFFFF; + } + } else { + timer_init(timer, &task->fifo, 1); /*下次置1 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_000000; + } + } + timer_settime(timer, 50); + } + if (i == 2) { /*光标ON */ + cons.cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + boxfill8(sheet->buf, sheet->bxsize, COL8_000000, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + cons.cur_c = -1; + } + if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/ + if (i == 8 + 256) { + /*退格键*/ + if (cons.cur_x > 16) { + /*用空格擦除光标后将光标前移一位*/ + cons_putchar(&cons, ' ', 0); + cons.cur_x -= 8; + } + } else if (i == 10 + 256) { + /*回车键*/ + /*将光标用空格擦除后换行 */ + cons_putchar(&cons, ' ', 0); + cmdline[cons.cur_x / 8 - 2] = 0; + cons_newline(&cons); + cons_runcmd(cmdline, &cons, fat, memtotal); /*运行命令*/ + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + } else { + /*一般字符*/ + if (cons.cur_x < 240) { + /*显示一个字符之后将光标后移一位*/ + cmdline[cons.cur_x / 8 - 2] = i - 256; + cons_putchar(&cons, i - 256, 1); + } + } + } + /*重新显示光标*/ + if (cons.cur_c >= 0) { + boxfill8(sheet->buf, sheet->bxsize, cons.cur_c, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + } + sheet_refresh(sheet, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16); + } + } +} + +void cons_putchar(struct CONSOLE *cons, int chr, char move) +{ + char s[2]; + s[0] = chr; + s[1] = 0; + if (s[0] == 0x09) { /*制表符*/ + for (;;) { + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1); + cons->cur_x += 8; + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + if (((cons->cur_x - 8) & 0x1f) == 0) { + break; /*被32整除则break*/ + } + } + } else if (s[0] == 0x0a) { /*换行*/ + cons_newline(cons); + } else if (s[0] == 0x0d) { /*回车*/ + /*先不做任何操作*/ + } else { /*一般字符*/ + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1); + if (move != 0) { + /* move为0时光标不后移*/ + cons->cur_x += 8; + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + } + } + return; +} + +void cons_newline(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + if (cons->cur_y < 28 + 112) { + cons->cur_y += 16; /*到下一行*/ + } else { + /*滚动*/ + for (y = 28; y < 28 + 112; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize]; + } + } + for (y = 28 + 112; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + } + cons->cur_x = 8; + return; +} + +void cons_putstr0(struct CONSOLE *cons, char *s) +{ + for (; *s != 0; s++) { + cons_putchar(cons, *s, 1); + } + return; +} + +void cons_putstr1(struct CONSOLE *cons, char *s, int l) +{ + int i; + for (i = 0; i < l; i++) { + cons_putchar(cons, s[i], 1); + } + return; +} + +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, unsigned int memtotal) +{ + if (strcmp(cmdline, "mem") == 0) { + cmd_mem(cons, memtotal); + } else if (strcmp(cmdline, "cls") == 0) { + cmd_cls(cons); + } else if (strcmp(cmdline, "dir") == 0 || strcmp(cmdline, "ls") == 0) { + cmd_dir(cons); + } else if (strncmp(cmdline, "type ", 5) == 0) { + cmd_type(cons, fat, cmdline); + } else if (cmdline[0] != 0) { + if (cmd_app(cons, fat, cmdline) == 0) { + /*不是命令,不是应用程序,也不是空行*/ + cons_putstr0(cons, "Bad command.\n\n"); + } + } + return; +} + +void cmd_mem(struct CONSOLE *cons, unsigned int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + char s[60]; + sprintf(s, "total %dMB\nfree %dKB\n\n", memtotal / (1024 * 1024), memman_total(memman) / 1024); + cons_putstr0(cons, s); + return; +} + +void cmd_cls(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + for (y = 28; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + cons->cur_y = 28; + return; +} + +void cmd_dir(struct CONSOLE *cons) +{ + struct FILEINFO *finfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600); + int i, j; + char s[30]; + for (i = 0; i < 224; i++) { + if (finfo[i].name[0] == 0x00) { + break; + } + if (finfo[i].name[0] != 0xe5) { + if ((finfo[i].type & 0x18) == 0) { + sprintf(s, "filename.ext %7d\n", finfo[i].size); + for (j = 0; j < 8; j++) { + s[j] = finfo[i].name[j]; + } + s[ 9] = finfo[i].ext[0]; + s[10] = finfo[i].ext[1]; + s[11] = finfo[i].ext[2]; + cons_putstr0(cons, s); + } + } + } + cons_newline(cons); + return; +} + +void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct FILEINFO *finfo = file_search(cmdline + 5, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + char *p; + if (finfo != 0) { + /*找到文件的情况*/ + p = (char *) memman_alloc_4k(memman, finfo->size); + file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); + cons_putstr1(cons, p, finfo->size); + memman_free_4k(memman, (int) p, finfo->size); + } else { + /*没有找到文件的情况*/ + cons_putstr0(cons, "File not found.\n"); + } + cons_newline(cons); + return; +} + +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct FILEINFO *finfo; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + char name[18], *p, *q; + struct TASK *task = task_now(); + int i, segsiz, datsiz, esp, dathrb; + struct SHTCTL *shtctl; + struct SHEET *sht; + + /*根据命令行生成文件名*/ + for (i = 0; i < 13; i++) { + if (cmdline[i] <= ' ') { + break; + } + name[i] = cmdline[i]; + } + name[i] = 0; /*暂且将文件名的后面置为0*/ + + /*寻找文件 */ + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + if (finfo == 0 && name[i -1]!= '.') { + /*由于找不到文件,故在文件名后面加上“.hrb”后重新寻找*/ + name[i ] = '.'; + name[i + 1] = 'H'; + name[i + 2] = 'R'; + name[i + 3] = 'B'; + name[i + 4] = 0; + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + } + + if (finfo != 0) { + /*找到文件的情况*/ + p = (char *) memman_alloc_4k(memman, finfo->size); + file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); + if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) { + segsiz = *((int *) (p + 0x0000)); + esp = *((int *) (p + 0x000c)); + datsiz = *((int *) (p + 0x0010)); + dathrb = *((int *) (p + 0x0014)); + q = (char *) memman_alloc_4k(memman, segsiz); + *((int *) 0xfe8) = (int) q; + set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); + set_segmdesc(gdt + 1004, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); + for (i = 0; i < datsiz; i++) { + q[esp + i] = p[dathrb + i]; + } + start_app(0x1b, 1003 * 8, esp, 1004 * 8, &(task->tss.esp0)); + shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + for (i = 0; i < MAX_SHEETS; i++) { + sht = &(shtctl->sheets0[i]); + if ((sht->flags & 0x11) == 0x11 && sht->task == task) { + /*找到被应用程序遗留的窗口*/ + sheet_free(sht); /*关闭*/ + } + } + timer_cancelall(&task->fifo); + memman_free_4k(memman, (int) q, segsiz); + } else { + cons_putstr0(cons, ".hrb file format error.\n"); + } + memman_free_4k(memman, (int) p, finfo->size); + cons_newline(cons); + return 1; + } + /*没有找到文件的情况*/ + return 0; +} + +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) +{ + int ds_base = *((int *) 0xfe8); + struct TASK *task = task_now(); + struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec); + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct SHEET *sht; + int *reg = &eax + 1; /* eax后面的地址*/ + /*强行改写通过PUSHAD保存的值*/ + /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */ + /* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ + int i; + + if (edx == 1) { + cons_putchar(cons, eax & 0xff, 1); + } else if (edx == 2) { + cons_putstr0(cons, (char *) ebx + ds_base); + } else if (edx == 3) { + cons_putstr1(cons, (char *) ebx + ds_base, ecx); + } else if (edx == 4) { + return &(task->tss.esp0); + } else if (edx == 5) { + sht = sheet_alloc(shtctl); + sht->task = task; + sht->flags |= 0x10; + sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax); + make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0); + sheet_slide(sht, 100, 50); + sheet_updown(sht, 3); /*背景层高度3位于task_a之上*/ + reg[7] = (int) sht; + } else if (edx == 6) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + putfonts8_asc(sht->buf, sht->bxsize, esi, edi, eax, (char *) ebp + ds_base); + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + ecx * 8, edi + 16); + } + } else if (edx == 7) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + boxfill8(sht->buf, sht->bxsize, ebp, eax, ecx, esi, edi); + if ((ebx & 1) == 0) { + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 8) { + memman_init((struct MEMMAN *) (ebx + ds_base)); + ecx &= 0xfffffff0; /*以16字节为单位*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 9) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + reg[7] = memman_alloc((struct MEMMAN *) (ebx + ds_base), ecx); + } else if (edx == 10) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 11) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + sht->buf[sht->bxsize * edi + esi] = eax; + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + 1, edi + 1); + } + } else if (edx == 12) { + sht = (struct SHEET *) ebx; + sheet_refresh(sht, eax, ecx, esi, edi); + } else if (edx == 13) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + hrb_api_linewin(sht, eax, ecx, esi, edi, ebp); + if ((ebx & 1) == 0) { + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 14) { + sheet_free((struct SHEET *) ebx); + } else if (edx == 15) { + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + if (eax != 0) { + task_sleep(task); /* FIFO为空,休眠并等待*/ + } else { + io_sti(); + reg[7] = -1; + return 0; + } + } + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1) { /*光标用定时器*/ + /*应用程序运行时不需要显示光标,因此总是将下次显示用的值置为1*/ + timer_init(cons->timer, &task->fifo, 1); /*下次置为1*/ + timer_settime(cons->timer, 50); + } + if (i == 2) { /*光标ON */ + cons->cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + cons->cur_c = -1; + } + if (i >= 256) { /*键盘数据(通过任务A)等*/ + reg[7] = i - 256; + return 0; + } + } + } else if (edx == 16) { + reg[7] = (int) timer_alloc(); + ((struct TIMER *) reg[7])->flags2 = 1; /*允许自动取消*/ + } else if (edx == 17) { + timer_init((struct TIMER *) ebx, &task->fifo, eax + 256); + } else if (edx == 18) { + timer_settime((struct TIMER *) ebx, eax); + } else if (edx == 19) { + timer_free((struct TIMER *) ebx); + } + return 0; +} + +int *inthandler0c(int *esp) +{ + struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec); + struct TASK *task = task_now(); + char s[30]; + cons_putstr0(cons, "\nINT 0C :\n Stack Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +int *inthandler0d(int *esp) +{ + struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec); + struct TASK *task = task_now(); + char s[30]; + cons_putstr0(cons, "\nINT 0D :\n General Protected Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col) +{ + int i, x, y, len, dx, dy; + + dx = x1 - x0; + dy = y1 - y0; + x = x0 << 10; + y = y0 << 10; + if (dx < 0) { + dx = - dx; + } + if (dy < 0) { + dy = - dy; + } + if (dx >= dy) { + len = dx + 1; + if (x0 > x1) { + dx = -1024; + } else { + dx = 1024; + } + if (y0 <= y1) { + dy = ((y1 - y0 + 1) << 10) / len; + } else { + dy = ((y1 - y0 - 1) << 10) / len; + } + } else { + len = dy + 1; + if (y0 > y1) { + dy = -1024; + } else { + dy = 1024; + } + if (x0 <= x1) { + dx = ((x1 - x0 + 1) << 10) / len; + } else { + dx = ((x1 - x0 - 1) << 10) / len; + } + } + + for (i = 0; i < len; i++) { + sht->buf[(y >> 10) * sht->bxsize + (x >> 10)] = col; + x += dx; + y += dy; + } + + return; +} diff --git a/25_day/dsctbl.c b/25_day/dsctbl.c new file mode 100644 index 0000000..05bfe89 --- /dev/null +++ b/25_day/dsctbl.c @@ -0,0 +1,60 @@ +/* GDT、IDT、descriptor table 关系处理 */ + +#include "bootpack.h" + +void init_gdtidt(void) +{ + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *) ADR_IDT; + int i; + + /* GDT初始化 */ + for (i = 0; i <= LIMIT_GDT / 8; i++) { + set_segmdesc(gdt + i, 0, 0, 0); + } + set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW); + set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER); + load_gdtr(LIMIT_GDT, ADR_GDT); + + /* IDT初始化 */ + for (i = 0; i <= LIMIT_IDT / 8; i++) { + set_gatedesc(idt + i, 0, 0, 0); + } + load_idtr(LIMIT_IDT, ADR_IDT); + + /* IDT设置*/ + set_gatedesc(idt + 0x0c, (int) asm_inthandler0c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x0d, (int) asm_inthandler0d, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x27, (int) asm_inthandler27, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x40, (int) asm_hrb_api, 2 * 8, AR_INTGATE32 + 0x60); + + return; +} + +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar) +{ + if (limit > 0xfffff) { + ar |= 0x8000; /* G_bit = 1 */ + limit /= 0x1000; + } + sd->limit_low = limit & 0xffff; + sd->base_low = base & 0xffff; + sd->base_mid = (base >> 16) & 0xff; + sd->access_right = ar & 0xff; + sd->limit_high = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0); + sd->base_high = (base >> 24) & 0xff; + return; +} + +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar) +{ + gd->offset_low = offset & 0xffff; + gd->selector = selector; + gd->dw_count = (ar >> 8) & 0xff; + gd->access_right = ar & 0xff; + gd->offset_high = (offset >> 16) & 0xffff; + return; +} diff --git a/25_day/fifo.c b/25_day/fifo.c new file mode 100644 index 0000000..8f28f4b --- /dev/null +++ b/25_day/fifo.c @@ -0,0 +1,63 @@ +/* FIFO */ + +#include "bootpack.h" + +#define FLAGS_OVERRUN 0x0001 + +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task) +/* FIFO缓冲区的初始化*/ +{ + fifo->size = size; + fifo->buf = buf; + fifo->free = size; /*空*/ + fifo->flags = 0; + fifo->p = 0; /*写入位置*/ + fifo->q = 0; /*读取位置*/ + fifo->task = task; /*有数据写入时需要唤醒的任务*/ + return; +} + +int fifo32_put(struct FIFO32 *fifo, int data) +/*向FIFO写入数据并累积起来*/ +{ + if (fifo->free == 0) { + /*没有空余空间,溢出*/ + fifo->flags |= FLAGS_OVERRUN; + return -1; + } + fifo->buf[fifo->p] = data; + fifo->p++; + if (fifo->p == fifo->size) { + fifo->p = 0; + } + fifo->free--; + if (fifo->task != 0) { + if (fifo->task->flags != 2) { /*如果任务处于休眠状态*/ + task_run(fifo->task, -1, 0); /*将任务唤醒*/ + } + } + return 0; +} + +int fifo32_get(struct FIFO32 *fifo) +/*从FIFO取得一个数据*/ +{ + int data; + if (fifo->free == fifo->size) { + /*当缓冲区为空的情况下返回-1*/ + return -1; + } + data = fifo->buf[fifo->q]; + fifo->q++; + if (fifo->q == fifo->size) { + fifo->q = 0; + } + fifo->free++; + return data; +} + +int fifo32_status(struct FIFO32 *fifo) +/*报告已经存储了多少数据*/ +{ + return fifo->size - fifo->free; +} diff --git a/25_day/file.c b/25_day/file.c new file mode 100644 index 0000000..c289350 --- /dev/null +++ b/25_day/file.c @@ -0,0 +1,74 @@ +/* 文件相关函数 */ + +#include "bootpack.h" + +void file_readfat(int *fat, unsigned char *img) +/*将磁盘映像中的FAT解压缩 */ +{ + int i, j = 0; + for (i = 0; i < 2880; i += 2) { + fat[i + 0] = (img[j + 0] | img[j + 1] << 8) & 0xfff; + fat[i + 1] = (img[j + 1] >> 4 | img[j + 2] << 4) & 0xfff; + j += 3; + } + return; +} + +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img) +{ + int i; + for (;;) { + if (size <= 512) { + for (i = 0; i < size; i++) { + buf[i] = img[clustno * 512 + i]; + } + break; + } + for (i = 0; i < 512; i++) { + buf[i] = img[clustno * 512 + i]; + } + size -= 512; + buf += 512; + clustno = fat[clustno]; + } + return; +} + +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max) +{ + int i, j; + char s[12]; + for (j = 0; j < 11; j++) { + s[j] = ' '; + } + j = 0; + for (i = 0; name[i] != 0; i++) { + if (j >= 11) { return 0; /*没有找到*/ } + if (name[i] == '.' && j <= 8) { + j = 8; + } else { + s[j] = name[i]; + if ('a' <= s[j] && s[j] <= 'z') { + /*将小写字母转换为大写字母*/ + s[j] -= 0x20; + } + j++; + } + } + for (i = 0; i < max; ) { + if (finfo[i].name[0] == 0x00) { + break; + } + if ((finfo[i].type & 0x18) == 0) { + for (j = 0; j < 11; j++) { + if (finfo[i].name[j] != s[j]) { + goto next; + } + } + return finfo + i; /*找到文件*/ + } + next: + i++; + } + return 0; /*没有找到*/ +} diff --git a/25_day/graphic.c b/25_day/graphic.c new file mode 100644 index 0000000..f2df123 --- /dev/null +++ b/25_day/graphic.c @@ -0,0 +1,157 @@ +/* 关于绘图部分的处理 */ + +#include "bootpack.h" + +void init_palette(void) +{ + static unsigned char table_rgb[16 * 3] = { + 0x00, 0x00, 0x00, /* 0:黑 */ + 0xff, 0x00, 0x00, /* 1:梁红 */ + 0x00, 0xff, 0x00, /* 2:亮绿 */ + 0xff, 0xff, 0x00, /* 3:亮黄 */ + 0x00, 0x00, 0xff, /* 4:亮蓝 */ + 0xff, 0x00, 0xff, /* 5:亮紫 */ + 0x00, 0xff, 0xff, /* 6:浅亮蓝 */ + 0xff, 0xff, 0xff, /* 7:白 */ + 0xc6, 0xc6, 0xc6, /* 8:亮灰 */ + 0x84, 0x00, 0x00, /* 9:暗红 */ + 0x00, 0x84, 0x00, /* 10:暗绿 */ + 0x84, 0x84, 0x00, /* 11:暗黄 */ + 0x00, 0x00, 0x84, /* 12:暗青 */ + 0x84, 0x00, 0x84, /* 13:暗紫 */ + 0x00, 0x84, 0x84, /* 14:浅暗蓝 */ + 0x84, 0x84, 0x84 /* 15:暗灰 */ + }; + set_palette(0, 15, table_rgb); + return; + + /* C语言中的static char语句只能用于数据,相当于汇编中的DB指令 */ +} + +void set_palette(int start, int end, unsigned char *rgb) +{ + int i, eflags; + eflags = io_load_eflags(); /* 记录中断许可标志的值 */ + io_cli(); /* 将中断许可标志置为0,禁止中断 */ + io_out8(0x03c8, start); + for (i = start; i <= end; i++) { + io_out8(0x03c9, rgb[0] / 4); + io_out8(0x03c9, rgb[1] / 4); + io_out8(0x03c9, rgb[2] / 4); + rgb += 3; + } + io_store_eflags(eflags); /* 复原中断许可标志 */ + return; +} + +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) +{ + int x, y; + for (y = y0; y <= y1; y++) { + for (x = x0; x <= x1; x++) + vram[y * xsize + x] = c; + } + return; +} + +void init_screen8(char *vram, int x, int y) +{ + boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28); + boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1); + + boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24); + boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4); + boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4); + boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5); + boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3); + boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3); + + boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24); + boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4); + boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3); + boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3); + return; +} + +void putfont8(char *vram, int xsize, int x, int y, char c, char *font) +{ + int i; + char *p, d /* data */; + for (i = 0; i < 16; i++) { + p = vram + (y + i) * xsize + x; + d = font[i]; + if ((d & 0x80) != 0) { p[0] = c; } + if ((d & 0x40) != 0) { p[1] = c; } + if ((d & 0x20) != 0) { p[2] = c; } + if ((d & 0x10) != 0) { p[3] = c; } + if ((d & 0x08) != 0) { p[4] = c; } + if ((d & 0x04) != 0) { p[5] = c; } + if ((d & 0x02) != 0) { p[6] = c; } + if ((d & 0x01) != 0) { p[7] = c; } + } + return; +} + +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s) +{ + extern char hankaku[4096]; + /* C语言中,字符串都是以0x00结尾 */ + for (; *s != 0x00; s++) { + putfont8(vram, xsize, x, y, c, hankaku + *s * 16); + x += 8; + } + return; +} + +void init_mouse_cursor8(char *mouse, char bc) +/* 鼠标的数据准备(16x16) */ +{ + static char cursor[16][16] = { + "**************..", + "*OOOOOOOOOOO*...", + "*OOOOOOOOOO*....", + "*OOOOOOOOO*.....", + "*OOOOOOOO*......", + "*OOOOOOO*.......", + "*OOOOOOO*.......", + "*OOOOOOOO*......", + "*OOOO**OOO*.....", + "*OOO*..*OOO*....", + "*OO*....*OOO*...", + "*O*......*OOO*..", + "**........*OOO*.", + "*..........*OOO*", + "............*OO*", + ".............***" + }; + int x, y; + + for (y = 0; y < 16; y++) { + for (x = 0; x < 16; x++) { + if (cursor[y][x] == '*') { + mouse[y * 16 + x] = COL8_000000; + } + if (cursor[y][x] == 'O') { + mouse[y * 16 + x] = COL8_FFFFFF; + } + if (cursor[y][x] == '.') { + mouse[y * 16 + x] = bc; + } + } + } + return; +} + +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize) +{ + int x, y; + for (y = 0; y < pysize; y++) { + for (x = 0; x < pxsize; x++) { + vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x]; + } + } + return; +} diff --git a/25_day/hankaku.txt b/25_day/hankaku.txt new file mode 100644 index 0000000..62d56f9 --- /dev/null +++ b/25_day/hankaku.txt @@ -0,0 +1,4609 @@ +OSASK̔ptHg𗬗p + +char 0x00 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x01 +........ +........ +..***... +.*...*.. +*.....*. +*.*.*.*. +*.*.*.*. +*.....*. +*.....*. +*.*.*.*. +*..*..*. +.*...*.. +..***... +........ +........ +........ + +char 0x02 +........ +........ +..***... +.*****.. +*******. +**.*.**. +**.*.**. +*******. +*******. +**.*.**. +***.***. +.*****.. +..***... +........ +........ +........ + +char 0x03 +........ +........ +........ +........ +.**.**.. +*******. +*******. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x04 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x05 +........ +........ +........ +........ +...*.... +..***... +.*.*.*.. +*******. +.*.*.*.. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x06 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +**.*.**. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x07 +........ +........ +........ +........ +........ +........ +...**... +..****.. +..****.. +...**... +........ +........ +........ +........ +........ +........ + +char 0x08 +******** +******** +******** +******** +******** +******** +***..*** +**....** +**....** +***..*** +******** +******** +******** +******** +******** +******** + +char 0x09 +........ +........ +........ +........ +........ +..****.. +.**..**. +.*....*. +.*....*. +.**..**. +..****.. +........ +........ +........ +........ +........ + +char 0x0a +******** +******** +******** +******** +******** +**....** +*..**..* +*.****.* +*.****.* +*..**..* +**....** +******** +******** +******** +******** +******** + +char 0x0b +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x0c +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ + +char 0x0d +........ +........ +....**.. +....***. +....*.** +....*.** +....*.*. +....*... +....*... +...**... +.****... +*****... +.***.... +........ +........ +........ + +char 0x0e +........ +........ +...***** +...***** +...*...* +...*...* +...*...* +...*...* +...*...* +...*...* +.***.*** +******** +.**..**. +........ +........ +........ + +char 0x0f +........ +........ +........ +........ +...*.... +.*.*.*.. +..***... +..*.*... +..***... +.*.*.*.. +...*.... +........ +........ +........ +........ +........ + +char 0x10 +........ +*....... +**...... +***..... +****.... +*****... +******.. +*******. +******.. +*****... +****.... +***..... +**...... +*....... +........ +........ + +char 0x11 +........ +......*. +.....**. +....***. +...****. +..*****. +.******. +*******. +.******. +..*****. +...****. +....***. +.....**. +......*. +........ +........ + +char 0x12 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ +........ + +char 0x13 +........ +........ +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +........ +........ +.*...*.. +.*...*.. +........ +........ + +char 0x14 +........ +..*****. +.*..*.*. +*...*.*. +*...*.*. +*...*.*. +*...*.*. +.*..*.*. +..***.*. +....*.*. +....*.*. +....*.*. +....*.*. +....*.*. +........ +........ + +char 0x15 +.*****.. +*.....*. +.*...... +..*..... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +....*... +.....*.. +*.....*. +.*****.. +........ + +char 0x16 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*******. +*******. +........ +........ + +char 0x17 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +.*****.. +........ +........ + +char 0x18 +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x19 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ + +char 0x1a +........ +........ +........ +........ +...*.... +....*... +.....*.. +*******. +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ + +char 0x1b +........ +........ +........ +........ +...*.... +..*..... +.*...... +*******. +.*...... +..*..... +...*.... +........ +........ +........ +........ +........ + +char 0x1c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*....... +*....... +*******. +........ +........ + +char 0x1d +........ +........ +........ +........ +........ +..*.*... +.*...*.. +*******. +.*...*.. +..*.*... +........ +........ +........ +........ +........ +........ + +char 0x1e +........ +........ +........ +........ +...*.... +...*.... +..***... +..***... +.*****.. +.*****.. +*******. +*******. +........ +........ +........ +........ + +char 0x1f +........ +........ +........ +........ +*******. +*******. +.*****.. +.*****.. +..***... +..***... +...*.... +...*.... +........ +........ +........ +........ + +char 0x20 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x21 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ +...*.... +...*.... +........ +........ + +char 0x22 +..*.*... +..*.*... +..*.*... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x23 +........ +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +........ +........ + +char 0x24 +...*.... +..***.*. +.*.*.**. +*..*..*. +*..*..*. +*..*.... +.*.*.... +..***... +...*.*.. +...*..*. +*..*..*. +*..*..*. +**.*.*.. +*.***... +...*.... +...*.... + +char 0x25 +.**...*. +*..*..*. +*..*.*.. +*..*.*.. +.**.*... +....*... +...*.... +...*.... +..*..... +..*.**.. +.*.*..*. +.*.*..*. +*..*..*. +*...**.. +........ +........ + +char 0x26 +........ +.***.... +*...*... +*...*... +*...*... +*..*.... +.**..... +.*...*** +*.*...*. +*..*..*. +*...*.*. +*....*.. +.*...**. +..***..* +........ +........ + +char 0x27 +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x28 +......*. +.....*.. +....*... +....*... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....*... +....*... +.....*.. +......*. +........ + +char 0x29 +*....... +.*...... +..*..... +..*..... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..*..... +..*..... +.*...... +*....... +........ + +char 0x2a +........ +........ +........ +........ +........ +...*.... +*..*..*. +.*.*.*.. +..***... +.*.*.*.. +*..*..*. +...*.... +........ +........ +........ +........ + +char 0x2b +........ +........ +........ +........ +........ +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ +........ +........ + +char 0x2c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x2d +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ +........ +........ +........ +........ +........ +........ + +char 0x2e +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x2f +......*. +......*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*...... +.*...... +*....... +*....... + +char 0x30 +........ +...**... +..*..*.. +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +...**... +........ +........ + +char 0x31 +........ +....*... +...**... +..*.*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +..*****. +........ +........ + +char 0x32 +........ +...**... +..*..*.. +.*....*. +.*....*. +......*. +.....*.. +....*... +...*.... +..*..... +..*..... +.*...... +.*...... +.******. +........ +........ + +char 0x33 +........ +...**... +..*..*.. +.*....*. +......*. +......*. +.....*.. +...**... +.....*.. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x34 +........ +....**.. +....**.. +....**.. +...*.*.. +...*.*.. +...*.*.. +..*..*.. +..*..*.. +.*...*.. +.******. +.....*.. +.....*.. +...****. +........ +........ + +char 0x35 +........ +.*****.. +.*...... +.*...... +.*...... +.*.**... +.**..*.. +......*. +......*. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x36 +........ +...**... +..*..*.. +.*....*. +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x37 +........ +.******. +.*....*. +.*....*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x38 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x39 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..**. +...**.*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x3a +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x3b +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x3c +........ +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +........ + +char 0x3d +........ +........ +........ +........ +........ +........ +*******. +........ +........ +*******. +........ +........ +........ +........ +........ +........ + +char 0x3e +........ +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +........ + +char 0x3f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.....*.. +....*... +...*.... +...*.... +........ +........ +...**... +...**... +........ +........ + +char 0x40 +........ +..***... +.*...*.. +*.....*. +*..**.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*..***.. +*....... +.*...**. +..***... +........ +........ + +char 0x41 +........ +...**... +...**... +...**... +...**... +..*..*.. +..*..*.. +..*..*.. +..*..*.. +.******. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x42 +........ +****.... +.*..*... +.*...*.. +.*...*.. +.*...*.. +.*..*... +.****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +*****... +........ +........ + +char 0x43 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*....... +*....... +*....... +*.....*. +.*....*. +.*...*.. +..***... +........ +........ + +char 0x44 +........ +*****... +.*...*.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...*.. +.*...*.. +*****... +........ +........ + +char 0x45 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x46 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...*.. +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x47 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*..****. +*.....*. +*.....*. +*.....*. +.*....*. +.*...**. +..***... +........ +........ + +char 0x48 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.******. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x49 +........ +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x4a +........ +...***** +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +*....*.. +.*..*... +..**.... +........ + +char 0x4b +........ +***..*** +.*....*. +.*...*.. +.*..*... +.*.*.... +.*.*.... +.**..... +.*.*.... +.*.*.... +.*..*... +.*...*.. +.*....*. +***..*** +........ +........ + +char 0x4c +........ +****.... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x4d +........ +**....** +.*....*. +.**..**. +.**..**. +.**..**. +.*.**.*. +.*.**.*. +.*.**.*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x4e +........ +**...*** +.*....*. +.**...*. +.**...*. +.*.*..*. +.*.*..*. +.*.*..*. +.*..*.*. +.*..*.*. +.*..*.*. +.*...**. +.*...**. +***...*. +........ +........ + +char 0x4f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x50 +........ +*****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +.****... +.*...... +.*...... +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x51 +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*..*..*. +*...*.*. +.*...*.. +..***.*. +........ +........ + +char 0x52 +........ +******.. +.*....*. +.*....*. +.*....*. +.*....*. +.*****.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x53 +........ +..***.*. +.*...**. +*.....*. +*.....*. +*....... +.*...... +..***... +.....*.. +......*. +*.....*. +*.....*. +**...*.. +*.***... +........ +........ + +char 0x54 +........ +*******. +*..*..*. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x55 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..****.. +........ +........ + +char 0x56 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...**... +...**... +........ +........ + +char 0x57 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x58 +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +..*..*.. +..*..*.. +..*..*.. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x59 +........ +***.***. +.*...*.. +.*...*.. +.*...*.. +..*.*... +..*.*... +..*.*... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x5a +........ +*******. +*....*.. +*....*.. +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*....*. +*.....*. +*******. +........ +........ + +char 0x5b +........ +..*****. +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*****. +........ + +char 0x5c +*....... +*....... +.*...... +.*...... +..*..... +..*..... +..*..... +...*.... +...*.... +....*... +....*... +.....*.. +.....*.. +.....*.. +......*. +......*. + +char 0x5d +........ +.*****.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.*****.. +........ + +char 0x5e +........ +...*.... +..*.*... +.*...*.. +*.....*. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x5f +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ + +char 0x60 +...*.... +....*... +.....*.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x61 +........ +........ +........ +........ +........ +.***.... +....*... +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +*...**.. +.***.**. +........ +........ + +char 0x62 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +........ +........ + +char 0x63 +........ +........ +........ +........ +........ +..**.... +.*..**.. +*....*.. +*....*.. +*....... +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x64 +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.**. +........ +........ + +char 0x65 +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +******.. +*....... +*.....*. +.*....*. +..****.. +........ +........ + +char 0x66 +....***. +...*.... +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x67 +........ +........ +........ +........ +........ +..**.**. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +.....*.. +.****... + +char 0x68 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x69 +........ +...*.... +...*.... +........ +........ +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6a +........ +.....*.. +.....*.. +........ +........ +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +....*... +....*... +..**.... + +char 0x6b +**...... +.*...... +.*...... +.*...... +.*...... +.*..***. +.*...*.. +.*..*... +.*.*.... +.**..... +.*.*.... +.*..*... +.*...*.. +***..**. +........ +........ + +char 0x6c +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6d +........ +........ +........ +........ +........ +****.**. +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +**.**.** +........ +........ + +char 0x6e +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x6f +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x70 +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +.*...... +***..... + +char 0x71 +........ +........ +........ +........ +........ +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +....***. + +char 0x72 +........ +........ +........ +........ +........ +**.***.. +.**...*. +.*....*. +.*...... +.*...... +.*...... +.*...... +.*...... +***..... +........ +........ + +char 0x73 +........ +........ +........ +........ +........ +.****.*. +*....**. +*.....*. +**...... +..***... +.....**. +*.....*. +**....*. +*.****.. +........ +........ + +char 0x74 +........ +........ +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....***. +........ +........ + +char 0x75 +........ +........ +........ +........ +........ +**...**. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...**. +..***.** +........ +........ + +char 0x76 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +........ +........ + +char 0x77 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x78 +........ +........ +........ +........ +........ +**...**. +.*...*.. +..*.*... +..*.*... +...*.... +..*.*... +..*.*... +.*...*.. +**...**. +........ +........ + +char 0x79 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...*.... +...*.... +.**..... + +char 0x7a +........ +........ +........ +........ +........ +*******. +*.....*. +*....*.. +....*... +...*.... +..*..... +.*....*. +*.....*. +*******. +........ +........ + +char 0x7b +........ +.....**. +....*... +...*.... +...*.... +...*.... +...*.... +.**..... +...*.... +...*.... +...*.... +...*.... +....*... +.....**. +........ +........ + +char 0x7c +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0x7d +........ +.**..... +...*.... +....*... +....*... +....*... +....*... +.....**. +....*... +....*... +....*... +....*... +...*.... +.**..... +........ +........ + +char 0x7e +........ +.***..*. +*...**.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x7f +........ +........ +........ +........ +...*.... +..*.*... +.*...*.. +*.....*. +*******. +*.....*. +*******. +........ +........ +........ +........ +........ + +char 0x80 +........ +..***... +.*...*.. +*.....*. +*....... +*....... +*....... +*....... +*....... +*....... +*....... +*.....*. +.*...*.. +..***... +...*.... +..*..... + +char 0x81 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x82 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x83 +........ +...*.... +..*.*... +.*...*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x84 +........ +........ +..*..*.. +..*..*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x85 +...*.... +....*... +.....*.. +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x86 +........ +...**... +..*..*.. +...**... +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x87 +........ +........ +........ +........ +........ +..****.. +.*....*. +*....... +*....... +*....... +*....... +*....... +.*....*. +..****.. +....*... +...*.... + +char 0x88 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x89 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8a +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8b +........ +........ +..*..*.. +..*..*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8c +........ +...*.... +..*.*... +.*...*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8d +...*.... +....*... +.....*.. +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8e +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x8f +........ +..***... +.*...*.. +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x90 +....**.. +....*... +...*.... +*******. +*....... +*....... +*....... +*....... +*****... +*....... +*....... +*....... +*....... +*******. +........ +........ + +char 0x91 +........ +........ +........ +........ +........ +.**..... +...***.. +...*..*. +.***..*. +*..****. +*..*.... +*..*.... +*..*..*. +.**.**.. +........ +........ + +char 0x92 +....**.. +...*.... +..*..... +..*.*... +..*.*... +..*.*... +*******. +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +........ +........ + +char 0x93 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x94 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x95 +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x96 +........ +...*.... +..*.*... +.*...*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x97 +...*.... +....*... +.....*.. +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x98 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +.*...*.. +.*...*.. +..*.*... +..*.*... +...*.... +...*.... +..*..... +..*..... +.*...... + +char 0x99 +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9a +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9b +........ +..*.*... +..*.*... +..*.*... +..****.. +.**.*.*. +*.*.*... +*.*.*... +*.*.*... +*.*.*... +*.*.*... +.**.*.*. +..****.. +..*.*... +..*.*... +..*.*... + +char 0x9c +........ +....**.. +...*..*. +..*..... +..*..... +..*..... +******.. +..*..... +..*..... +..*..... +.**..... +*.*..... +*.**..*. +.*..**.. +........ +........ + +char 0x9d +........ +*.....*. +*.....*. +.*...*.. +..*.*... +...*.... +*******. +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x9e +........ +***..... +*..*.... +*...*... +*...*... +*...*... +*..*.*.. +***..*.. +*..***** +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +........ +........ + +char 0x9f +........ +....**.. +...*..*. +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +...*.... +*..*.... +.**..... +........ +........ + +char 0xa0 +....**.. +....*... +...*.... +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0xa1 +....**.. +....*... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xa2 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa3 +....**.. +....*... +...*.... +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0xa4 +........ +...*..*. +..*.*.*. +..*..*.. +........ +*****... +*....*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0xa5 +...*..*. +..*.*.*. +..*..*.. +........ +*.....*. +**....*. +**....*. +*.*...*. +*..*..*. +*..*..*. +*...*.*. +*....**. +*....**. +*.....*. +........ +........ + +char 0xa6 +........ +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +*******. +........ +........ + +char 0xa7 +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +*******. +........ +........ + +char 0xa8 +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +..*..... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*....... +*....... +*....... +........ +........ + +char 0xaa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +......*. +......*. +......*. +........ +........ + +char 0xab +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +.****... +.....*.. +..***... +.*...... +.*****.. +........ +........ + +char 0xac +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +...**... +..*.*... +.*..*... +.*****.. +....*... +........ +........ + +char 0xad +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xae +........ +........ +........ +........ +...*..*. +..*..*.. +.*..*... +*..*.... +*..*.... +.*..*... +..*..*.. +...*..*. +........ +........ +........ +........ + +char 0xaf +........ +........ +........ +........ +*..*.... +.*..*... +..*..*.. +...*..*. +...*..*. +..*..*.. +.*..*... +*..*.... +........ +........ +........ +........ + +char 0xb0 +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. + +char 0xb1 +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. + +char 0xb2 +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* + +char 0xb3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb6 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb7 +........ +........ +........ +........ +........ +........ +........ +******.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb8 +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb9 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xba +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbb +........ +........ +........ +........ +........ +........ +........ +******.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +******.. +........ +........ +........ +........ +........ +........ + +char 0xbd +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******.. +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xbe +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +........ +........ +........ +........ +........ +........ + +char 0xbf +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc0 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc1 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc4 +........ +........ +........ +........ +........ +........ +........ +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc6 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xc8 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xc9 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xca +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xcb +........ +........ +........ +........ +........ +........ +........ +******** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcd +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xce +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcf +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xd0 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd1 +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd3 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xd5 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd6 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd8 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd9 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xda +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xdb +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdc +........ +........ +........ +........ +........ +........ +........ +........ +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdd +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... + +char 0xde +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** + +char 0xdf +******** +******** +******** +******** +******** +******** +******** +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xea +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xeb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xec +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xed +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xee +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xef +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfc +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfd +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfe +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xff +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ diff --git a/25_day/hello.nas b/25_day/hello.nas new file mode 100644 index 0000000..b4e9576 --- /dev/null +++ b/25_day/hello.nas @@ -0,0 +1,16 @@ +[INSTRSET "i486p"] +[BITS 32] + MOV ECX,msg + MOV EDX,1 +putloop: + MOV AL,[CS:ECX] + CMP AL,0 + JE fin + INT 0x40 + ADD ECX,1 + JMP putloop +fin: + MOV EDX,4 + INT 0x40 +msg: + DB "hello",0 diff --git a/25_day/hello2.nas b/25_day/hello2.nas new file mode 100644 index 0000000..5e1e58c --- /dev/null +++ b/25_day/hello2.nas @@ -0,0 +1,9 @@ +[INSTRSET "i486p"] +[BITS 32] + MOV EDX,2 + MOV EBX,msg + INT 0x40 + MOV EDX,4 + INT 0x40 +msg: + DB "hello",0 diff --git a/25_day/hello3.c b/25_day/hello3.c new file mode 100644 index 0000000..97d3236 --- /dev/null +++ b/25_day/hello3.c @@ -0,0 +1,12 @@ +void api_putchar(int c); +void api_end(void); + +void HariMain(void) +{ + api_putchar('h'); + api_putchar('e'); + api_putchar('l'); + api_putchar('l'); + api_putchar('o'); + api_end(); +} diff --git a/25_day/hello4.c b/25_day/hello4.c new file mode 100644 index 0000000..7fb73de --- /dev/null +++ b/25_day/hello4.c @@ -0,0 +1,8 @@ +void api_putstr0(char *s); +void api_end(void); + +void HariMain(void) +{ + api_putstr0("hello, world\n"); + api_end(); +} diff --git a/25_day/hello5.nas b/25_day/hello5.nas new file mode 100644 index 0000000..ee62330 --- /dev/null +++ b/25_day/hello5.nas @@ -0,0 +1,20 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "hello5.nas"] + + GLOBAL _HariMain + +[SECTION .text] + +_HariMain: + MOV EDX,2 + MOV EBX,msg + INT 0x40 + MOV EDX,4 + INT 0x40 + +[SECTION .data] + +msg: + DB "hello, world", 0x0a, 0 diff --git a/25_day/int.c b/25_day/int.c new file mode 100644 index 0000000..c717372 --- /dev/null +++ b/25_day/int.c @@ -0,0 +1,37 @@ +/*初始化关系 */ + +#include "bootpack.h" +#include + +void init_pic(void) +/* PIC初始化 */ +{ + io_out8(PIC0_IMR, 0xff ); /* 禁止所有中断 */ + io_out8(PIC1_IMR, 0xff ); /* 禁止所有中断 */ + + io_out8(PIC0_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC0_ICW2, 0x20 ); /* IRQ0-7由INT20-27接收 */ + io_out8(PIC0_ICW3, 1 << 2); /* PIC1由IRQ2相连 */ + io_out8(PIC0_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC1_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC1_ICW2, 0x28 ); /* IRQ8-15由INT28-2f接收 */ + io_out8(PIC1_ICW3, 2 ); /* PIC1由IRQ2连接 */ + io_out8(PIC1_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外全部禁止 */ + io_out8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中断 */ + + return; +} + +void inthandler27(int *esp) +/* PIC0中断的不完整策略 */ +/* 这个中断在Athlon64X2上通过芯片组提供的便利,只需执行一次 */ +/* 这个中断只是接收,不执行任何操作 */ +/* 为什么不处理? + → 因为这个中断可能是电气噪声引发的、只是处理一些重要的情况。*/ +{ + io_out8(PIC0_OCW2, 0x67); /* 通知PIC的IRQ-07(参考7-1) */ + return; +} diff --git a/25_day/ipl10.nas b/25_day/ipl10.nas new file mode 100644 index 0000000..7108a21 --- /dev/null +++ b/25_day/ipl10.nas @@ -0,0 +1,109 @@ +; haribote-ipl +; TAB=4 + +CYLS EQU 10 ; 声明CYLS=10 + + ORG 0x7c00 ; 指明程序装载地址 + +; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code + + JMP entry + DB 0x90 + DB "HARIBOTE" ; 启动扇区名称(8字节) + DW 512 ; 每个扇区(sector)大小(必须512字节) + DB 1 ; 簇(cluster)大小(必须为1个扇区) + DW 1 ; FAT起始位置(一般为第一个扇区) + DB 2 ; FAT个数(必须为2) + DW 224 ; 根目录大小(一般为224项) + DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512) + DB 0xf0 ; 磁盘类型(必须为0xf0) + DW 9 ; FAT的长度(必??9扇区) + DW 18 ; 一个磁道(track)有几个扇区(必须为18) + DW 2 ; 磁头数(必??2) + DD 0 ; 不使用分区,必须是0 + DD 2880 ; 重写一次磁盘大小 + DB 0,0,0x29 ; 意义不明(固定) + DD 0xffffffff ; (可能是)卷标号码 + DB "HARIBOTEOS " ; 磁盘的名称(必须为11字?,不足填空格) + DB "FAT12 " ; 磁盘格式名称(必??8字?,不足填空格) + RESB 18 ; 先空出18字节 + +; 程序主体 + +entry: + MOV AX,0 ; 初始化寄存器 + MOV SS,AX + MOV SP,0x7c00 + MOV DS,AX + +; 读取磁盘 + + MOV AX,0x0820 + MOV ES,AX + MOV CH,0 ; 柱面0 + MOV DH,0 ; 磁头0 + MOV CL,2 ; 扇区2 + +readloop: + MOV SI,0 ; 记录失败次数寄存器 + +retry: + MOV AH,0x02 ; AH=0x02 : 读入磁盘 + MOV AL,1 ; 1个扇区 + MOV BX,0 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 调用磁盘BIOS + JNC next ; 没出错则跳转到fin + ADD SI,1 ; 往SI加1 + CMP SI,5 ; 比较SI与5 + JAE error ; SI >= 5 跳转到error + MOV AH,0x00 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 重置驱动器 + JMP retry +next: + MOV AX,ES ; 把内存地址后移0x200(512/16十六进制转换) + ADD AX,0x0020 + MOV ES,AX ; ADD ES,0x020因为没有ADD ES,只能通过AX进行 + ADD CL,1 ; 往CL里面加1 + CMP CL,18 ; 比较CL与18 + JBE readloop ; CL <= 18 跳转到readloop + MOV CL,1 + ADD DH,1 + CMP DH,2 + JB readloop ; DH < 2 跳转到readloop + MOV DH,0 + ADD CH,1 + CMP CH,CYLS + JB readloop ; CH < CYLS 跳转到readloop + +; 读取完毕,跳转到haribote.sys执行! + MOV [0x0ff0],CH ; IPLがどこまで読んだのかをメモ + JMP 0xc200 + +error: + MOV SI,msg + +putloop: + MOV AL,[SI] + ADD SI,1 ; 给SI加1 + CMP AL,0 + JE fin + MOV AH,0x0e ; 显示一个文字 + MOV BX,15 ; 指定字符颜色 + INT 0x10 ; 调用显卡BIOS + JMP putloop + +fin: + HLT ; 让CPU停止,等待指令 + JMP fin ; 无限循环 + +msg: + DB 0x0a, 0x0a ; 换行两次 + DB "load error" + DB 0x0a ; 换行 + DB 0 + + RESB 0x7dfe-$ ; 填写0x00直到0x001fe + + DB 0x55, 0xaa diff --git a/25_day/keyboard.c b/25_day/keyboard.c new file mode 100644 index 0000000..eb5140a --- /dev/null +++ b/25_day/keyboard.c @@ -0,0 +1,44 @@ +/* 键盘控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *keyfifo; +int keydata0; + +void inthandler21(int *esp) +{ + int data; + io_out8(PIC0_OCW2, 0x61); /* 把IRQ-01接收信号结束的信息通知给PIC */ + data = io_in8(PORT_KEYDAT); + fifo32_put(keyfifo, data + keydata0); + return; +} + +#define PORT_KEYSTA 0x0064 +#define KEYSTA_SEND_NOTREADY 0x02 +#define KEYCMD_WRITE_MODE 0x60 +#define KBC_MODE 0x47 + +void wait_KBC_sendready(void) +{ + /* 等待键盘控制电路准备完毕 */ + for (;;) { + if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) { + break; + } + } + return; +} + +void init_keyboard(struct FIFO32 *fifo, int data0) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + keyfifo = fifo; + keydata0 = data0; + /* 键盘控制器的初始化 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, KBC_MODE); + return; +} diff --git a/25_day/lines.c b/25_day/lines.c new file mode 100644 index 0000000..83e7ceb --- /dev/null +++ b/25_day/lines.c @@ -0,0 +1,29 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +void api_closewin(int win); +int api_getkey(int mode); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win, i; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "lines"); + for (i = 0; i < 8; i++) { + api_linewin(win + 1, 8, 26, 77, i * 9 + 26, i); + api_linewin(win + 1, 88, 26, i * 9 + 88, 89, i); + } + api_refreshwin(win, 6, 26, 154, 90); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_closewin(win); + api_end(); +} diff --git a/25_day/make.bat b/25_day/make.bat new file mode 100644 index 0000000..e489766 --- /dev/null +++ b/25_day/make.bat @@ -0,0 +1 @@ +..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/25_day/memory.c b/25_day/memory.c new file mode 100644 index 0000000..54a447a --- /dev/null +++ b/25_day/memory.c @@ -0,0 +1,162 @@ +/* �������֌W */ + +#include "bootpack.h" + +#define EFLAGS_AC_BIT 0x00040000 +#define CR0_CACHE_DISABLE 0x60000000 + +unsigned int memtest(unsigned int start, unsigned int end) +{ + char flg486 = 0; + unsigned int eflg, cr0, i; + + /* 确认CPU是386还是486以上的 */ + eflg = io_load_eflags(); + eflg |= EFLAGS_AC_BIT; /* AC-bit = 1 */ + io_store_eflags(eflg); + eflg = io_load_eflags(); + if ((eflg & EFLAGS_AC_BIT) != 0) { + /* 如果是386,即使设定AC=1,AC的值还会自动回到0 */ + flg486 = 1; + } + + eflg &= ~EFLAGS_AC_BIT; /* AC-bit = 0 */ + io_store_eflags(eflg); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 |= CR0_CACHE_DISABLE; /* 禁止缓存 */ + store_cr0(cr0); + } + + i = memtest_sub(start, end); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 &= ~CR0_CACHE_DISABLE; /* 允许缓存 */ + store_cr0(cr0); + } + + return i; +} + +void memman_init(struct MEMMAN *man) +{ + man->frees = 0; /* 可用信息数目 */ + man->maxfrees = 0; /* 用于观察可用状况:frees的最大值 */ + man->lostsize = 0; /* 释放失败的内存的大小总和 */ + man->losts = 0; /* 释放失败次数 */ + return; +} + +unsigned int memman_total(struct MEMMAN *man) +/* 报告空余内存大小的合计 */ +{ + unsigned int i, t = 0; + for (i = 0; i < man->frees; i++) { + t += man->free[i].size; + } + return t; +} + +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size) +/* 分配 */ +{ + unsigned int i, a; + for (i = 0; i < man->frees; i++) { + if (man->free[i].size >= size) { + /* 找到了足够大的内存 */ + a = man->free[i].addr; + man->free[i].addr += size; + man->free[i].size -= size; + if (man->free[i].size == 0) { + /* 如果free[i]变成了0,就减掉一条可用信息 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 代入结构体 */ + } + } + return a; + } + } + return 0; /* 没有可用空间 */ +} + +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size) +/* 释放 */ +{ + int i, j; + /* 为便于归纳内存,将free[]按照addr的顺序排列 */ + /* 所以,先决定应该放在哪里 */ + for (i = 0; i < man->frees; i++) { + if (man->free[i].addr > addr) { + break; + } + } + /* free[i - 1].addr < addr < free[i].addr */ + if (i > 0) { + /* 前面有可用内存 */ + if (man->free[i - 1].addr + man->free[i - 1].size == addr) { + /* 可以与前面的可用内存归纳到一起 */ + man->free[i - 1].size += size; + if (i < man->frees) { + /* 后面也有 */ + if (addr + size == man->free[i].addr) { + /* 也可以与后面的可用内存归纳到一起 */ + man->free[i - 1].size += man->free[i].size; + /* man->free[i]删除 */ + /* free[i]变成0后归纳到前面去 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 结构体赋值 */ + } + } + } + return 0; /* 成功完成 */ + } + } + /* 不能与前面的可用空间归纳到一起 */ + if (i < man->frees) { + /* 后面还有 */ + if (addr + size == man->free[i].addr) { + /* 可以与后面的内容归纳到一起 */ + man->free[i].addr = addr; + man->free[i].size += size; + return 0; /* 成功完成 */ + } + } + /* 既不能与前面归纳到一起,也不能与后面归纳到一起 */ + if (man->frees < MEMMAN_FREES) { + /* free[i]之后的,向后移动,腾出一点可用空间 */ + for (j = man->frees; j > i; j--) { + man->free[j] = man->free[j - 1]; + } + man->frees++; + if (man->maxfrees < man->frees) { + man->maxfrees = man->frees; /* 更新最大值 */ + } + man->free[i].addr = addr; + man->free[i].size = size; + return 0; /* 成功完成 */ + } + /* 不能往后移动 */ + man->losts++; + man->lostsize += size; + return -1; /* 失败 */ +} + +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size) +{ + unsigned int a; + size = (size + 0xfff) & 0xfffff000; + a = memman_alloc(man, size); + return a; +} + +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size) +{ + int i; + size = (size + 0xfff) & 0xfffff000; + i = memman_free(man, addr, size); + return i; +} diff --git a/25_day/mouse.c b/25_day/mouse.c new file mode 100644 index 0000000..0c6403e --- /dev/null +++ b/25_day/mouse.c @@ -0,0 +1,76 @@ +/* 鼠标控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *mousefifo; +int mousedata0; + +void inthandler2c(int *esp) +/* 来自PS/2鼠标的中断 */ +{ + int data; + io_out8(PIC1_OCW2, 0x64); /* 把IRQ-12接收信号结束的信息通知给PIC1 */ + io_out8(PIC0_OCW2, 0x62); /* 把IRQ-02接收信号结束的信息通知给PIC0 */ + data = io_in8(PORT_KEYDAT); + fifo32_put(mousefifo, data + mousedata0); + return; +} + +#define KEYCMD_SENDTO_MOUSE 0xd4 +#define MOUSECMD_ENABLE 0xf4 + +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + mousefifo = fifo; + mousedata0 = data0; + /* 鼠标有效 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, MOUSECMD_ENABLE); + /* 顺利的话,ACK(0xfa)会被发送*/ + mdec->phase = 0; /* 等待鼠标的0xfa的阶段*/ +return; +} + +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat) +{ + if (mdec->phase == 0) { + /* 等待鼠标的0xfa的阶段 */ + if (dat == 0xfa) { + mdec->phase = 1; + } + return 0; + } + if (mdec->phase == 1) { + /* 等待鼠标第一字节的阶段 */ + mdec->buf[0] = dat; + mdec->phase = 2; + return 0; + } + if (mdec->phase == 2) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[1] = dat; + mdec->phase = 3; + return 0; + } + if (mdec->phase == 3) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[2] = dat; + mdec->phase = 1; + mdec->btn = mdec->buf[0] & 0x07; + mdec->x = mdec->buf[1]; + mdec->y = mdec->buf[2]; + if ((mdec->buf[0] & 0x10) != 0) { + mdec->x |= 0xffffff00; + } + if ((mdec->buf[0] & 0x20) != 0) { + mdec->y |= 0xffffff00; + } + mdec->y = - mdec->y; /* 鼠标的y方向与画面符号相反 */ + return 1; + } + /* 应该不可能到这里来 */ + return -1; +} diff --git a/25_day/mtask.c b/25_day/mtask.c new file mode 100644 index 0000000..b518641 --- /dev/null +++ b/25_day/mtask.c @@ -0,0 +1,201 @@ +/* 多任务管理 */ + +#include "bootpack.h" + +struct TASKCTL *taskctl; +struct TIMER *task_timer; + +struct TASK *task_now(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + return tl->tasks[tl->now]; +} + +void task_add(struct TASK *task) +{ + struct TASKLEVEL *tl = &taskctl->level[task->level]; + tl->tasks[tl->running] = task; + tl->running++; + task->flags = 2; /*活动中*/ + return; +} + +void task_remove(struct TASK *task) +{ + int i; + struct TASKLEVEL *tl = &taskctl->level[task->level]; + + /*寻找task所在的位置*/ + for (i = 0; i < tl->running; i++) { + if (tl->tasks[i] == task) { + /*在这里 */ + break; + } + } + + tl->running--; + if (i < tl->now) { + tl->now--; /*需要移动成员,要相应地处理 */ + } + if (tl->now >= tl->running) { + /*如果now的值出现异常,则进行修正*/ + tl->now = 0; + } + task->flags = 1; /* 休眠中 */ + + /* 移动 */ + for (; i < tl->running; i++) { + tl->tasks[i] = tl->tasks[i + 1]; + } + return; +} + +void task_switchsub(void) +{ + int i; + /*寻找最上层的LEVEL */ + for (i = 0; i < MAX_TASKLEVELS; i++) { + if (taskctl->level[i].running > 0) { + break; /*找到了*/ + } + } + taskctl->now_lv = i; + taskctl->lv_change = 0; + return; +} + +void task_idle(void) +{ + for (;;) { + io_hlt(); + } +} + +struct TASK *task_init(struct MEMMAN *memman) +{ + int i; + struct TASK *task, *idle; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + + + taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL)); + for (i = 0; i < MAX_TASKS; i++) { + taskctl->tasks0[i].flags = 0; + taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8; + set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32); + } + for (i = 0; i < MAX_TASKLEVELS; i++) { + taskctl->level[i].running = 0; + taskctl->level[i].now = 0; + } + + task = task_alloc(); + task->flags = 2; /*活动中标志*/ + task->priority = 2; /* 0.02秒*/ + task->level = 0; /*最高LEVEL */ + task_add(task); + task_switchsub(); /* LEVEL 设置*/ + load_tr(task->sel); + task_timer = timer_alloc(); + timer_settime(task_timer, task->priority); + + idle = task_alloc(); + idle->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024; + idle->tss.eip = (int) &task_idle; + idle->tss.es = 1 * 8; + idle->tss.cs = 2 * 8; + idle->tss.ss = 1 * 8; + idle->tss.ds = 1 * 8; + idle->tss.fs = 1 * 8; + idle->tss.gs = 1 * 8; + task_run(idle, MAX_TASKLEVELS - 1, 1); + + return task; +} + +struct TASK *task_alloc(void) +{ + int i; + struct TASK *task; + for (i = 0; i < MAX_TASKS; i++) { + if (taskctl->tasks0[i].flags == 0) { + task = &taskctl->tasks0[i]; + task->flags = 1; /*正在使用的标志*/ + task->tss.eflags = 0x00000202; /* IF = 1; */ + task->tss.eax = 0; /*这里先置为0*/ + task->tss.ecx = 0; + task->tss.edx = 0; + task->tss.ebx = 0; + task->tss.ebp = 0; + task->tss.esi = 0; + task->tss.edi = 0; + task->tss.es = 0; + task->tss.ds = 0; + task->tss.fs = 0; + task->tss.gs = 0; + task->tss.ldtr = 0; + task->tss.iomap = 0x40000000; + task->tss.ss0 = 0; + return task; + } + } + return 0; /*全部正在使用*/ +} + +void task_run(struct TASK *task, int level, int priority) +{ + if (level < 0) { + level = task->level; /*不改变LEVEL */ + } + if (priority > 0) { + task->priority = priority; + } + if (task->flags == 2 && task->level != level) { + /*改变活动中的LEVEL */ + task_remove(task); /*这里执行之后flag的值会变为1,于是下面的if语句块也会被执行*/ + } + if (task->flags != 2) { + /*从休眠状态唤醒的情形*/ + task->level = level; + task_add(task); + } + taskctl->lv_change = 1; /*下次任务切换时检查LEVEL */ + return; +} + +void task_switch(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + struct TASK *new_task, *now_task = tl->tasks[tl->now]; + tl->now++; + if (tl->now == tl->running) { + tl->now = 0; + } + if (taskctl->lv_change != 0) { + task_switchsub(); + tl = &taskctl->level[taskctl->now_lv]; + } + new_task = tl->tasks[tl->now]; + timer_settime(task_timer, new_task->priority); + if (new_task != now_task) { + farjmp(0, new_task->sel); + } + return; +} + +void task_sleep(struct TASK *task) +{ + struct TASK *now_task; + if (task->flags == 2) { + /*如果处于活动状态*/ + now_task = task_now(); + task_remove(task); /*执行此语句的话flags将变为1 */ + if (task == now_task) { + /*如果是让自己休眠,则需要进行任务切换*/ + task_switchsub(); + now_task = task_now(); /*在设定后获取当前任务的值*/ + farjmp(0, now_task->sel); + } + } + return; +} diff --git a/25_day/naskfunc.nas b/25_day/naskfunc.nas new file mode 100644 index 0000000..d32a472 --- /dev/null +++ b/25_day/naskfunc.nas @@ -0,0 +1,307 @@ +; naskfunc +; TAB=4 + +[FORMAT "WCOFF"] ; 制作目标文件的模式 +[INSTRSET "i486p"] ; 使用到486为止的指令 +[BITS 32] ; 3制作32位模式用的机器语言 +[FILE "naskfunc.nas"] ; 文件名 + + GLOBAL _io_hlt, _io_cli, _io_sti, _io_stihlt + GLOBAL _io_in8, _io_in16, _io_in32 + GLOBAL _io_out8, _io_out16, _io_out32 + GLOBAL _io_load_eflags, _io_store_eflags + GLOBAL _load_gdtr, _load_idtr + GLOBAL _load_cr0, _store_cr0 + GLOBAL _load_tr + GLOBAL _asm_inthandler20, _asm_inthandler21 + GLOBAL _asm_inthandler27, _asm_inthandler2c + GLOBAL _asm_inthandler0c, _asm_inthandler0d + GLOBAL _asm_end_app, _memtest_sub + GLOBAL _farjmp, _farcall + GLOBAL _asm_hrb_api, _start_app + EXTERN _inthandler20, _inthandler21 + EXTERN _inthandler27, _inthandler2c + EXTERN _inthandler0c, _inthandler0d + EXTERN _hrb_api + +[SECTION .text] + +_io_hlt: ; void io_hlt(void); + HLT + RET + +_io_cli: ; void io_cli(void); + CLI + RET + +_io_sti: ; void io_sti(void); + STI + RET + +_io_stihlt: ; void io_stihlt(void); + STI + HLT + RET + +_io_in8: ; int io_in8(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AL,DX + RET + +_io_in16: ; int io_in16(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AX,DX + RET + +_io_in32: ; int io_in32(int port); + MOV EDX,[ESP+4] ; port + IN EAX,DX + RET + +_io_out8: ; void io_out8(int port, int data); + MOV EDX,[ESP+4] ; port + MOV AL,[ESP+8] ; data + OUT DX,AL + RET + +_io_out16: ; void io_out16(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,AX + RET + +_io_out32: ; void io_out32(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,EAX + RET + +_io_load_eflags: ; int io_load_eflags(void); + PUSHFD ; PUSH EFLAGS + POP EAX + RET + +_io_store_eflags: ; void io_store_eflags(int eflags); + MOV EAX,[ESP+4] + PUSH EAX + POPFD ; POP EFLAGS + RET + +_load_gdtr: ; void load_gdtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LGDT [ESP+6] + RET + +_load_idtr: ; void load_idtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LIDT [ESP+6] + RET + +_load_cr0: ; int load_cr0(void); + MOV EAX,CR0 + RET + +_store_cr0: ; void store_cr0(int cr0); + MOV EAX,[ESP+4] + MOV CR0,EAX + RET + +_load_tr: ; void load_tr(int tr); + LTR [ESP+4] ; tr + RET + +_asm_inthandler20: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler20 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler21: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler21 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler27: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler27 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler2c: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler2c + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler0c: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0c + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; 在INT 0x0c中也需要这句 + IRETD + +_asm_inthandler0d: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0d + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; INT 0x0d需要这句 + IRETD + +_memtest_sub: ; unsigned int memtest_sub(unsigned int start, unsigned int end) + PUSH EDI ; (由于还要使用EBX, ESI, EDI) + PUSH ESI + PUSH EBX + MOV ESI,0xaa55aa55 ; pat0 = 0xaa55aa55; + MOV EDI,0x55aa55aa ; pat1 = 0x55aa55aa; + MOV EAX,[ESP+12+4] ; i = start; +mts_loop: + MOV EBX,EAX + ADD EBX,0xffc ; p = i + 0xffc; + MOV EDX,[EBX] ; old = *p; + MOV [EBX],ESI ; *p = pat0; + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP EDI,[EBX] ; if (*p != pat1) goto fin; + JNE mts_fin + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP ESI,[EBX] ; if (*p != pat0) goto fin; + JNE mts_fin + MOV [EBX],EDX ; *p = old; + ADD EAX,0x1000 ; i += 0x1000; + CMP EAX,[ESP+12+8] ; if (i <= end) goto mts_loop; + JBE mts_loop + POP EBX + POP ESI + POP EDI + RET +mts_fin: + MOV [EBX],EDX ; *p = old; + POP EBX + POP ESI + POP EDI + RET + +_farjmp: ; void farjmp(int eip, int cs); + JMP FAR [ESP+4] ; eip, cs + RET + +_farcall: ; void farcall(int eip, int cs); + CALL FAR [ESP+4] ; eip, cs + RET + +_asm_hrb_api: + STI + PUSH DS + PUSH ES + PUSHAD ; 用于保存的PUSH + PUSHAD ; 用于向hrb_api传值的PUSH + MOV AX,SS + MOV DS,AX ; 将操作系统用段地址存入DS和ES + MOV ES,AX + CALL _hrb_api + CMP EAX,0 ; 当EAX不为0时程序结束 + JNE _asm_end_app + ADD ESP,32 + POPAD + POP ES + POP DS + IRETD +_asm_end_app: +; EAX为tss.esp0的地址 + MOV ESP,[EAX] + MOV DWORD [EAX+4],0 + POPAD + RET ; 返回cmd_app + +_start_app: ; void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); + PUSHAD ; 将32位寄存器的值全部保存起来 + MOV EAX,[ESP+36] ; 应用程序用EIP + MOV ECX,[ESP+40] ; 应用程序用CS + MOV EDX,[ESP+44] ; 应用程序用ESP + MOV EBX,[ESP+48] ; 应用程序用DS/SS + MOV EBP,[ESP+52] ; tss.esp0的地址 + MOV [EBP ],ESP ; 保存操作系统用ESP + MOV [EBP+4],SS ; 保存操作系统用SS + MOV ES,BX + MOV DS,BX + MOV FS,BX + MOV GS,BX +; 下面调整栈,以免用RETF跳转到应用程序 + OR ECX,3 ; 将应用程序用段号和3进行OR运算 + OR EBX,3 ; 将应用程序用段号和3进行OR运算 + PUSH EBX ; 应用程序的SS + PUSH EDX ; 应用程序的ESP + PUSH ECX ; 应用程序的CS + PUSH EAX ; 应用程序的EIP + RETF +; 应用程序结束后不会回到这里 diff --git a/25_day/noodle.c b/25_day/noodle.c new file mode 100644 index 0000000..13b9033 --- /dev/null +++ b/25_day/noodle.c @@ -0,0 +1,42 @@ +#include + +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +int api_getkey(int mode); +int api_alloctimer(void); +void api_inittimer(int timer, int data); +void api_settimer(int timer, int time); +void api_end(void); + +void HariMain(void) +{ + char *buf, s[12]; + int win, timer, sec = 0, min = 0, hou = 0; + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "noodle"); + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (;;) { + sprintf(s, "%5d:%02d:%02d", hou, min, sec); + api_boxfilwin(win, 28, 27, 115, 41, 7);/*白色*/ + api_putstrwin(win, 28, 27, 0, 11, s); /*黑色*/ + api_settimer(timer, 100); /* 1秒 */ + if (api_getkey(1) != 128) { + break; + } + sec++; + if (sec == 60) { + sec = 0; + min++; + if (min == 60) { + min = 0; + hou++; + } + } + } + api_end(); +} diff --git a/25_day/sheet.c b/25_day/sheet.c new file mode 100644 index 0000000..a51c756 --- /dev/null +++ b/25_day/sheet.c @@ -0,0 +1,217 @@ +/* sheet */ + +#include "bootpack.h" + +#define SHEET_USE 1 + +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize) +{ + struct SHTCTL *ctl; + int i; + ctl = (struct SHTCTL *) memman_alloc_4k(memman, sizeof (struct SHTCTL)); + if (ctl == 0) { + goto err; + } + ctl->map = (unsigned char *) memman_alloc_4k(memman, xsize * ysize); + if (ctl->map == 0) { + memman_free_4k(memman, (int) ctl, sizeof (struct SHTCTL)); + goto err; + } + ctl->vram = vram; + ctl->xsize = xsize; + ctl->ysize = ysize; + ctl->top = -1; /* 没有一张SHEET */ + for (i = 0; i < MAX_SHEETS; i++) { + ctl->sheets0[i].flags = 0; /* 标记为未使用 */ + ctl->sheets0[i].ctl = ctl; /* 记录所属*/ + } +err: + return ctl; +} + +struct SHEET *sheet_alloc(struct SHTCTL *ctl) +{ + struct SHEET *sht; + int i; + for (i = 0; i < MAX_SHEETS; i++) { + if (ctl->sheets0[i].flags == 0) { + sht = &ctl->sheets0[i]; + sht->flags = SHEET_USE; /* 标记为正在使用*/ + sht->height = -1; /* 隐藏 */ + sht->task = 0; /*不使用自动关闭功能*/ + return sht; + } + } + return 0; /* 所有的SHEET都处于正在使用状态*/ +} + +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv) +{ + sht->buf = buf; + sht->bxsize = xsize; + sht->bysize = ysize; + sht->col_inv = col_inv; + return; +} + +void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1; + unsigned char *buf, sid, *map = ctl->map; + struct SHEET *sht; + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= ctl->top; h++) { + sht = ctl->sheets[h]; + sid = sht - ctl->sheets0; /* 将进行了减法计算的地址作为图层号码使用 */ + buf = sht->buf; + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } + if (by1 > sht->bysize) { by1 = sht->bysize; } + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (buf[by * sht->bxsize + bx] != sht->col_inv) { + map[vy * ctl->xsize + vx] = sid; + } + } + } + } + return; +} + +void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0, int h1) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1; + unsigned char *buf, *vram = ctl->vram, *map = ctl->map, sid; + struct SHEET *sht; + + /* 如果refresh的范围超出了画面则修正 */ + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= h1; h++) { + sht = ctl->sheets[h]; + buf = sht->buf; + sid = sht - ctl->sheets0; + + /* 使用vx0~vy1,对bx0~by1进行倒推 */ + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } /* 处理刷新范围在图层外侧 */ + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } /* 应对不同的重叠方式 */ + if (by1 > sht->bysize) { by1 = sht->bysize; } + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + } + } + return; +} + +void sheet_updown(struct SHEET *sht, int height) +{ + struct SHTCTL *ctl = sht->ctl; + int h, old = sht->height; /* 存储设置前的高度信息 */ + if (height > ctl->top + 1) { + height = ctl->top + 1; + } + if (height < -1) { + height = -1; + } + sht->height = height;/* 设定高度 */ + + /* 下面主要是进行sheets[]的重新排列 */ + if (old > height) { /* 比以前低 */ + if (height >= 0) { + /* 把中间的往上提 */ + for (h = old; h > height; h--) { + ctl->sheets[h] = ctl->sheets[h - 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1, old); + } else { /* 隐藏 */ + if (ctl->top > old) { + /* 把上面的降下来 */ + for (h = old; h < ctl->top; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + } + ctl->top--; /* 由于显示中的图层减少了一个,所以最上面的图层高度下降 */ + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0, old - 1); + } + } else if (old < height) { /* 比以前高 */ + if (old >= 0) { + /* 把中间的拉下去 */ + for (h = old; h < height; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + } else { /* 由隐藏状态转为显示状态 */ + /* 将已在上面的提上来 */ + for (h = ctl->top; h >= height; h--) { + ctl->sheets[h + 1] = ctl->sheets[h]; + ctl->sheets[h + 1]->height = h + 1; + } + ctl->sheets[height] = sht; + ctl->top++; /* 由于已显示的图层增加了1个,所以最上面的图层高度增加 */ + } + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height, height); /* 按新图层信息重新绘制画面 */ + } + return; +} + +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1) +{ + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面*/ + sheet_refreshsub(sht->ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1, sht->height, sht->height); + } + return; +} + +void sheet_slide(struct SHEET *sht, int vx0, int vy0) +{ + struct SHTCTL *ctl = sht->ctl; + int old_vx0 = sht->vx0, old_vy0 = sht->vy0; + sht->vx0 = vx0; + sht->vy0 = vy0; + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面 */ + sheet_refreshmap(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0); + sheet_refreshmap(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height); + sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0, sht->height - 1); + sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height, sht->height); + } + return; +} + +void sheet_free(struct SHEET *sht) +{ + if (sht->height >= 0) { + sheet_updown(sht, -1); /* 如果处于显示状态,则先设定为隐藏 */ + } + sht->flags = 0; /* "未使用"标志 */ + return; +} diff --git a/25_day/star1.c b/25_day/star1.c new file mode 100644 index 0000000..8d80ffa --- /dev/null +++ b/25_day/star1.c @@ -0,0 +1,18 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_point(int win, int x, int y, int col); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "star1"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + api_point(win, 75, 59, 3);/*黄色*/ + api_end(); +} diff --git a/25_day/stars.c b/25_day/stars.c new file mode 100644 index 0000000..dc38b2b --- /dev/null +++ b/25_day/stars.c @@ -0,0 +1,24 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_point(int win, int x, int y, int col); +void api_end(void); + +int rand(void); /*产生0~32767之间的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win, x, y, 3);/*黄色*/ + } + api_end(); +} diff --git a/25_day/stars2.c b/25_day/stars2.c new file mode 100644 index 0000000..94a029e --- /dev/null +++ b/25_day/stars2.c @@ -0,0 +1,26 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_point(int win, int x, int y, int col); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_end(void); + +int rand(void); /*产生0~32767的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars2"); + api_boxfilwin(win + 1, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win + 1, x, y, 3);/*黄色*/ + } + api_refreshwin(win, 6, 26, 144, 94); + api_end(); +} diff --git a/25_day/timer.c b/25_day/timer.c new file mode 100644 index 0000000..9018ac8 --- /dev/null +++ b/25_day/timer.c @@ -0,0 +1,169 @@ +/* 定时器 */ + +#include "bootpack.h" + +#define PIT_CTRL 0x0043 +#define PIT_CNT0 0x0040 + +struct TIMERCTL timerctl; + +#define TIMER_FLAGS_ALLOC 1 /* 已配置状态 */ +#define TIMER_FLAGS_USING 2 /* 定时器运行中 */ + +void init_pit(void) +{ + int i; + struct TIMER *t; + io_out8(PIT_CTRL, 0x34); + io_out8(PIT_CNT0, 0x9c); + io_out8(PIT_CNT0, 0x2e); + timerctl.count = 0; + for (i = 0; i < MAX_TIMER; i++) { + timerctl.timers0[i].flags = 0; /* 没有使用 */ + } + t = timer_alloc(); /* 取得一个 */ + t->timeout = 0xffffffff; + t->flags = TIMER_FLAGS_USING; + t->next = 0; /* 末尾 */ + timerctl.t0 = t; /* 因为现在只有哨兵,所以他就在最前面*/ + timerctl.next = 0xffffffff; /* 因为只有哨兵,所以下一个超时时刻就是哨兵的时刻 */ + return; +} + +struct TIMER *timer_alloc(void) +{ + int i; + for (i = 0; i < MAX_TIMER; i++) { + if (timerctl.timers0[i].flags == 0) { + timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; + timerctl.timers0[i].flags2 = 0; + return &timerctl.timers0[i]; + } + } + return 0; /* 没找到 */ +} + +void timer_free(struct TIMER *timer) +{ + timer->flags = 0; /* 未使用 */ + return; +} + +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data) +{ + timer->fifo = fifo; + timer->data = data; + return; +} + +void timer_settime(struct TIMER *timer, unsigned int timeout) +{ + int e; + struct TIMER *t, *s; + timer->timeout = timeout + timerctl.count; + timer->flags = TIMER_FLAGS_USING; + e = io_load_eflags(); + io_cli(); + t = timerctl.t0; + if (timer->timeout <= t->timeout) { + /* 插入最前面的情况 */ + timerctl.t0 = timer; + timer->next = t; /* 下面是设定t */ + timerctl.next = timer->timeout; + io_store_eflags(e); + return; + } + for (;;) { + s = t; + t = t->next; + if (timer->timeout <= t->timeout) { + /* 插入s和t之间的情况 */ + s->next = timer; /* s下一个是timer */ + timer->next = t; /* timer的下一个是t */ + io_store_eflags(e); + return; + } + } +} + +void inthandler20(int *esp) +{ + struct TIMER *timer; + char ts = 0; + io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00接收信号结束的信息通知给PIC */ + timerctl.count++; + if (timerctl.next > timerctl.count) { + return; + } + timer = timerctl.t0; /* 首先把最前面的地址赋给timer */ + for (;;) { + /* 因为timers的定时器都处于运行状态,所以不确认flags */ + if (timer->timeout > timerctl.count) { + break; + } + /* 超时 */ + timer->flags = TIMER_FLAGS_ALLOC; + if (timer != task_timer) { + fifo32_put(timer->fifo, timer->data); + } else { + ts = 1; /* mt_timer超时*/ + } + timer = timer->next; /* 将下一个定时器的地址赋给timer*/ + } + timerctl.t0 = timer; + timerctl.next = timer->timeout; + if (ts != 0) { + task_switch(); + } + return; +} + +int timer_cancel(struct TIMER *timer) +{ + int e; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + if (timer->flags == TIMER_FLAGS_USING) { /*是否需要取消?*/ + if (timer == timerctl.t0) { + /*第一个定时器的取消处理*/ + t = timer->next; + timerctl.t0 = t; + timerctl.next = t->timeout; + } else { + /*非第一个定时器的取消处理*/ + /*找到timer前一个定时器*/ + t = timerctl.t0; + for (;;) { + if (t->next == timer) { + break; + } + t = t->next; + } + t->next = timer->next; + /*将之前“timer的下一个”指向“timer的下一个”*/ + } + timer->flags = TIMER_FLAGS_ALLOC; + io_store_eflags(e); + return 1; /*取消处理成功*/ + } + io_store_eflags(e); + return 0; /*不需要取消处理*/ +} + +void timer_cancelall(struct FIFO32 *fifo) +{ + int e, i; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + for (i = 0; i < MAX_TIMER; i++) { + t = &timerctl.timers0[i]; + if (t->flags != 0 && t->flags2 != 0 && t->fifo == fifo) { + timer_cancel(t); + timer_free(t); + } + } + io_store_eflags(e); + return; +} diff --git a/25_day/walk.c b/25_day/walk.c new file mode 100644 index 0000000..6b106b4 --- /dev/null +++ b/25_day/walk.c @@ -0,0 +1,35 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +void api_closewin(int win); +int api_getkey(int mode); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "walk"); + api_boxfilwin(win, 4, 24, 155, 95, 0);/*黑色*/ + x = 76; + y = 56; + api_putstrwin(win, x, y, 3, 1, "*");/*黄色*/ + for (;;) { + i = api_getkey(1); + api_putstrwin(win, x, y, 0 , 1, "*"); /*用黑色擦除*/ + if (i == '4' && x > 4) { x -= 8; } + if (i == '6' && x < 148) { x += 8; } + if (i == '8' && y > 24) { y -= 8; } + if (i == '2' && y < 80) { y += 8; } + if (i == 0x0a) { break; } /*按回车键结束*/ + api_putstrwin(win, x, y, 3 , 1, "*");/*黄色*/ + } + api_closewin(win); + api_end(); +} diff --git a/25_day/window.c b/25_day/window.c new file mode 100644 index 0000000..4d70578 --- /dev/null +++ b/25_day/window.c @@ -0,0 +1,118 @@ +/* 窗口相关函数 */ + +#include "bootpack.h" + +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act) +{ + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, xsize - 1, 0 ); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, xsize - 2, 1 ); + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, 0, ysize - 1); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, 1, ysize - 2); + boxfill8(buf, xsize, COL8_848484, xsize - 2, 1, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, xsize - 1, 0, xsize - 1, ysize - 1); + boxfill8(buf, xsize, COL8_C6C6C6, 2, 2, xsize - 3, ysize - 3); + boxfill8(buf, xsize, COL8_848484, 1, ysize - 2, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, 0, ysize - 1, xsize - 1, ysize - 1); + make_wtitle8(buf, xsize, title, act); + return; +} + +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act) +{ + static char closebtn[14][16] = { + "OOOOOOOOOOOOOOO@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQQQ@@QQQQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "O$$$$$$$$$$$$$$@", + "@@@@@@@@@@@@@@@@" + }; + int x, y; + char c, tc, tbc; + if (act != 0) { + tc = COL8_FFFFFF; + tbc = COL8_000084; + } else { + tc = COL8_C6C6C6; + tbc = COL8_848484; + } + boxfill8(buf, xsize, tbc, 3, 3, xsize - 4, 20); + putfonts8_asc(buf, xsize, 24, 4, tc, title); + for (y = 0; y < 14; y++) { + for (x = 0; x < 16; x++) { + c = closebtn[y][x]; + if (c == '@') { + c = COL8_000000; + } else if (c == '$') { + c = COL8_848484; + } else if (c == 'Q') { + c = COL8_C6C6C6; + } else { + c = COL8_FFFFFF; + } + buf[(5 + y) * xsize + (xsize - 21 + x)] = c; + } + } + return; +} + +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l) +{ + boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15); + putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); + sheet_refresh(sht, x, y, x + l * 8, y + 16); + return; +} + +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c) +{ + int x1 = x0 + sx, y1 = y0 + sy; + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3); + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1); + boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0); + return; +} + +void change_wtitle8(struct SHEET *sht, char act) +{ + int x, y, xsize = sht->bxsize; + char c, tc_new, tbc_new, tc_old, tbc_old, *buf = sht->buf; + if (act != 0) { + tc_new = COL8_FFFFFF; + tbc_new = COL8_000084; + tc_old = COL8_C6C6C6; + tbc_old = COL8_848484; + } else { + tc_new = COL8_C6C6C6; + tbc_new = COL8_848484; + tc_old = COL8_FFFFFF; + tbc_old = COL8_000084; + } + for (y = 3; y <= 20; y++) { + for (x = 3; x <= xsize - 4; x++) { + c = buf[y * xsize + x]; + if (c == tc_old && x <= xsize - 22) { + c = tc_new; + } else if (c == tbc_old) { + c = tbc_new; + } + buf[y * xsize + x] = c; + } + } + sheet_refresh(sht, 3, 3, xsize, 21); + return; +} diff --git a/25_day/winhelo.c b/25_day/winhelo.c new file mode 100644 index 0000000..6d7fb0a --- /dev/null +++ b/25_day/winhelo.c @@ -0,0 +1,11 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_end(void); + +char buf[150 * 50]; + +void HariMain(void) +{ + int win; + win = api_openwin(buf, 150, 50, -1, "hello"); + api_end(); +} diff --git a/25_day/winhelo2.c b/25_day/winhelo2.c new file mode 100644 index 0000000..f00b007 --- /dev/null +++ b/25_day/winhelo2.c @@ -0,0 +1,15 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_end(void); + +char buf[150 * 50]; + +void HariMain(void) +{ + int win; + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 3); /*黄色*/ + api_putstrwin(win, 28, 28, 0 /*黑色*/, 12, "hello, world"); + api_end(); +} diff --git a/25_day/winhelo3.c b/25_day/winhelo3.c new file mode 100644 index 0000000..527ec01 --- /dev/null +++ b/25_day/winhelo3.c @@ -0,0 +1,19 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win; + + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 6); /*浅蓝色*/ + api_putstrwin(win, 28, 28, 0 , 12, "hello, world");/*黑色*/ + api_end(); +} \ No newline at end of file From d84bab78e1601f83ae7ba393f7b9b37c6497e6f7 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 10:32:51 +0800 Subject: [PATCH 11/83] =?UTF-8?q?=E8=9C=82=E9=B8=A3=E5=99=A8=E5=8F=91?= =?UTF-8?q?=E5=A3=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 24_day/console.c | 12 ++++++++++++ 25_day/Makefile | 18 +++++++++++++++++- 25_day/a_nask.nas | 7 +++++++ 25_day/beepdown.c | 24 ++++++++++++++++++++++++ 25_day/beepup.c | 22 ++++++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 25_day/beepdown.c create mode 100644 25_day/beepup.c diff --git a/24_day/console.c b/24_day/console.c index ab3f80a..ceb2fc4 100644 --- a/24_day/console.c +++ b/24_day/console.c @@ -429,6 +429,18 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int timer_settime((struct TIMER *) ebx, eax); } else if (edx == 19) { timer_free((struct TIMER *) ebx); + } else if (edx == 20) { + if (eax == 0) { + i = io_in8(0x61); + io_out8(0x61, i & 0x0d); + } else { + i = 1193180000 / eax; + io_out8(0x43, 0xb6); + io_out8(0x42, i & 0xff); + io_out8(0x42, i >> 8); + i = io_in8(0x61); + io_out8(0x61, (i | 0x03) & 0x0f); + } } return 0; } diff --git a/25_day/Makefile b/25_day/Makefile index 4e81e55..c77e73f 100644 --- a/25_day/Makefile +++ b/25_day/Makefile @@ -155,10 +155,24 @@ noodle.bim : noodle.obj a_nask.obj Makefile noodle.hrb : noodle.bim Makefile $(BIM2HRB) noodle.bim noodle.hrb 40k +beepdown.bim : beepdown.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:beepdown.bim stack:1k map:beepdown.map \ + beepdown.obj a_nask.obj + +beepdown.hrb : beepdown.bim Makefile + $(BIM2HRB) beepdown.bim beepdown.hrb 40k + +beepup.bim : beepup.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:beepup.bim stack:1k map:beepup.map \ + beepup.obj a_nask.obj + +beepup.hrb : beepup.bim Makefile + $(BIM2HRB) beepup.bim beepup.hrb 40k + haribote.img : ipl10.bin haribote.sys Makefile \ hello.hrb hello2.hrb a.hrb hello3.hrb hello4.hrb hello5.hrb \ winhelo.hrb winhelo2.hrb winhelo3.hrb star1.hrb stars.hrb stars2.hrb \ - lines.hrb walk.hrb noodle.hrb + lines.hrb walk.hrb noodle.hrb beepdown.hrb beepup.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:ipl10.bin len:512 from:0 to:0 \ copy from:haribote.sys to:@: \ @@ -179,6 +193,8 @@ haribote.img : ipl10.bin haribote.sys Makefile \ copy from:lines.hrb to:@: \ copy from:walk.hrb to:@: \ copy from:noodle.hrb to:@: \ + copy from:beepdown.hrb to:@: \ + copy from:beepup.hrb to:@: \ imgout:haribote.img # 其他指令 diff --git a/25_day/a_nask.nas b/25_day/a_nask.nas index 56fe642..9e63654 100644 --- a/25_day/a_nask.nas +++ b/25_day/a_nask.nas @@ -21,6 +21,7 @@ GLOBAL _api_inittimer GLOBAL _api_settimer GLOBAL _api_freetimer + GLOBAL _api_beep [SECTION .text] @@ -221,3 +222,9 @@ _api_freetimer: ; void api_freetimer(int timer); INT 0x40 POP EBX RET + +_api_beep: ; void api_beep(int tone); + MOV EDX,20 + MOV EAX,[ESP+4] ; tone + INT 0x40 + RET diff --git a/25_day/beepdown.c b/25_day/beepdown.c new file mode 100644 index 0000000..db1aa59 --- /dev/null +++ b/25_day/beepdown.c @@ -0,0 +1,24 @@ +void api_end(void); +int api_getkey(int mode); +int api_alloctimer(void); +void api_inittimer(int timer, int data); +void api_settimer(int timer, int time); +void api_beep(int tone); + +void HariMain(void) +{ + int i, timer; + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (i = 20000000; i >= 20000; i -= i / 100) { + /* 20KHz~20Hz,即人类可以听到的声音范围*/ + /* i以1%的速度递减*/ + api_beep(i); + api_settimer(timer, 1); /* 0.01秒*/ + if (api_getkey(1) != 128) { + break; + } + } + api_beep(0); + api_end(); +} diff --git a/25_day/beepup.c b/25_day/beepup.c new file mode 100644 index 0000000..d14ccb6 --- /dev/null +++ b/25_day/beepup.c @@ -0,0 +1,22 @@ +void api_end(void); +int api_getkey(int mode); +int api_alloctimer(void); +void api_inittimer(int timer, int data); +void api_settimer(int timer, int time); +void api_beep(int tone); + +void HariMain(void) +{ + int i, timer; + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (i = 20000; i <= 20000000; i += i / 100) { + api_beep(i); + api_settimer(timer, 1); /* 0.01秒*/ + if (api_getkey(1) != 128) { + break; + } + } + api_beep(0); + api_end(); +} From 908570a673f24b1862d8bfa9cb05a44328d0de3d Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 10:38:37 +0800 Subject: [PATCH 12/83] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9B=B4=E5=A4=9A?= =?UTF-8?q?=E7=9A=84=E9=A2=9C=E8=89=B2=EF=BC=881=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 25_day/Makefile | 10 +++++++++- 25_day/color.c | 27 +++++++++++++++++++++++++++ 25_day/graphic.c | 14 ++++++++++++-- 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 25_day/color.c diff --git a/25_day/Makefile b/25_day/Makefile index c77e73f..719005f 100644 --- a/25_day/Makefile +++ b/25_day/Makefile @@ -169,10 +169,17 @@ beepup.bim : beepup.obj a_nask.obj Makefile beepup.hrb : beepup.bim Makefile $(BIM2HRB) beepup.bim beepup.hrb 40k +color.bim : color.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:color.bim stack:1k map:color.map \ + color.obj a_nask.obj + +color.hrb : color.bim Makefile + $(BIM2HRB) color.bim color.hrb 56k + haribote.img : ipl10.bin haribote.sys Makefile \ hello.hrb hello2.hrb a.hrb hello3.hrb hello4.hrb hello5.hrb \ winhelo.hrb winhelo2.hrb winhelo3.hrb star1.hrb stars.hrb stars2.hrb \ - lines.hrb walk.hrb noodle.hrb beepdown.hrb beepup.hrb + lines.hrb walk.hrb noodle.hrb beepdown.hrb beepup.hrb color.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:ipl10.bin len:512 from:0 to:0 \ copy from:haribote.sys to:@: \ @@ -195,6 +202,7 @@ haribote.img : ipl10.bin haribote.sys Makefile \ copy from:noodle.hrb to:@: \ copy from:beepdown.hrb to:@: \ copy from:beepup.hrb to:@: \ + copy from:color.hrb to:@: \ imgout:haribote.img # 其他指令 diff --git a/25_day/color.c b/25_day/color.c new file mode 100644 index 0000000..c004c14 --- /dev/null +++ b/25_day/color.c @@ -0,0 +1,27 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +int api_getkey(int mode); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win, x, y, r, g, b; + api_initmalloc(); + buf = api_malloc(144 * 164); + win = api_openwin(buf, 144, 164, -1, "color"); + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) { + r = x * 2; + g = y * 2; + b = 0; + buf[(x + 8) + (y + 28) * 144] = 16 + (r / 43) + (g / 43) * 6 + (b / 43) * 36; + } + } + api_refreshwin(win, 8, 28, 136, 156); + api_getkey(1); /*等待按下任意键*/ + api_end(); +} diff --git a/25_day/graphic.c b/25_day/graphic.c index f2df123..4bd6979 100644 --- a/25_day/graphic.c +++ b/25_day/graphic.c @@ -22,10 +22,20 @@ void init_palette(void) 0x00, 0x84, 0x84, /* 14:浅暗蓝 */ 0x84, 0x84, 0x84 /* 15:暗灰 */ }; + unsigned char table2[216 * 3]; + int r, g, b; set_palette(0, 15, table_rgb); + for (b = 0; b < 6; b++) { + for (g = 0; g < 6; g++) { + for (r = 0; r < 6; r++) { + table2[(r + g * 6 + b * 36) * 3 + 0] = r * 51; + table2[(r + g * 6 + b * 36) * 3 + 1] = g * 51; + table2[(r + g * 6 + b * 36) * 3 + 2] = b * 51; + } + } + } + set_palette(16, 231, table2); return; - - /* C语言中的static char语句只能用于数据,相当于汇编中的DB指令 */ } void set_palette(int start, int end, unsigned char *rgb) From c8a0464c520d7dac3f2f7294b52526ce41a8febd Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 10:45:55 +0800 Subject: [PATCH 13/83] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9B=B4=E5=A4=9A?= =?UTF-8?q?=E7=9A=84=E9=A2=9C=E8=89=B2=EF=BC=882=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 25_day/Makefile | 10 +++++++++- 25_day/color2.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 25_day/color2.c diff --git a/25_day/Makefile b/25_day/Makefile index 719005f..a53ff0f 100644 --- a/25_day/Makefile +++ b/25_day/Makefile @@ -176,10 +176,17 @@ color.bim : color.obj a_nask.obj Makefile color.hrb : color.bim Makefile $(BIM2HRB) color.bim color.hrb 56k +color2.bim : color2.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:color2.bim stack:1k map:color2.map \ + color2.obj a_nask.obj + +color2.hrb : color2.bim Makefile + $(BIM2HRB) color2.bim color2.hrb 56k + haribote.img : ipl10.bin haribote.sys Makefile \ hello.hrb hello2.hrb a.hrb hello3.hrb hello4.hrb hello5.hrb \ winhelo.hrb winhelo2.hrb winhelo3.hrb star1.hrb stars.hrb stars2.hrb \ - lines.hrb walk.hrb noodle.hrb beepdown.hrb beepup.hrb color.hrb + lines.hrb walk.hrb noodle.hrb beepdown.hrb beepup.hrb color.hrb color2.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:ipl10.bin len:512 from:0 to:0 \ copy from:haribote.sys to:@: \ @@ -203,6 +210,7 @@ haribote.img : ipl10.bin haribote.sys Makefile \ copy from:beepdown.hrb to:@: \ copy from:beepup.hrb to:@: \ copy from:color.hrb to:@: \ + copy from:color2.hrb to:@: \ imgout:haribote.img # 其他指令 diff --git a/25_day/color2.c b/25_day/color2.c new file mode 100644 index 0000000..c063768 --- /dev/null +++ b/25_day/color2.c @@ -0,0 +1,42 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +int api_getkey(int mode); +void api_end(void); + +unsigned char rgb2pal(int r, int g, int b, int x, int y); + +void HariMain(void) +{ + char *buf; + int win, x, y; + api_initmalloc(); + buf = api_malloc(144 * 164); + win = api_openwin(buf, 144, 164, -1, "color2"); + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) { + buf[(x + 8) + (y + 28) * 144] = rgb2pal(x * 2, y * 2, 0, x, y); + } + } + api_refreshwin(win, 8, 28, 136, 156); + api_getkey(1); /*等待按下任意键*/ + api_end(); +} + +unsigned char rgb2pal(int r, int g, int b, int x, int y) +{ + static int table[4] = { 3, 1, 0, 2 }; + int i; + x &= 1; /*判断是偶数还是奇数*/ + y &= 1; + i = table[x + y * 2]; /*用来生成中间色的常量*/ + r = (r * 21) / 256; /* r为0~20*/ + g = (g * 21) / 256; + b = (b * 21) / 256; + r = (r + i) / 4; /* r为0~5*/ + g = (g + i) / 4; + b = (b + i) / 4; + return 16 + r + g * 6 + b * 36; +} From b30660628236fdd2440f8c33f044986ddd81eb72 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 10:48:03 +0800 Subject: [PATCH 14/83] =?UTF-8?q?=E7=AA=97=E5=8F=A3=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 25_day/console.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/25_day/console.c b/25_day/console.c index ab3f80a..30017c8 100644 --- a/25_day/console.c +++ b/25_day/console.c @@ -348,8 +348,8 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int sht->flags |= 0x10; sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax); make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0); - sheet_slide(sht, 100, 50); - sheet_updown(sht, 3); /*背景层高度3位于task_a之上*/ + sheet_slide(sht, (shtctl->xsize - esi) / 2, (shtctl->ysize - edi) / 2); + sheet_updown(sht, shtctl->top); /*将窗口图层高度指定为当前鼠标所在图层的高度,鼠标移到上层*/ reg[7] = (int) sht; } else if (edx == 6) { sht = (struct SHEET *) (ebx & 0xfffffffe); From d046ca64a489c8eeec1301da8fbcc423b90c1b3e Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 10:57:30 +0800 Subject: [PATCH 15/83] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E8=A1=8C=E7=AA=97=E5=8F=A3=EF=BC=881=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 25_day/bootpack.c | 69 ++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/25_day/bootpack.c b/25_day/bootpack.c index 0bff4b5..9d5c075 100644 --- a/25_day/bootpack.c +++ b/25_day/bootpack.c @@ -19,9 +19,9 @@ void HariMain(void) unsigned int memtotal; struct MOUSE_DEC mdec; struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; - unsigned char *buf_back, buf_mouse[256], *buf_win, *buf_cons; - struct SHEET *sht_back, *sht_mouse, *sht_win, *sht_cons; - struct TASK *task_a, *task_cons; + unsigned char *buf_back, buf_mouse[256], *buf_win, *buf_cons[2]; + struct SHEET *sht_back, *sht_mouse, *sht_win, *sht_cons[2]; + struct TASK *task_a, *task_cons[2]; struct TIMER *timer; static char keytable0[0x80] = { 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0, 0, @@ -78,23 +78,27 @@ void HariMain(void) init_screen8(buf_back, binfo->scrnx, binfo->scrny); /* sht_cons */ - sht_cons = sheet_alloc(shtctl); - buf_cons = (unsigned char *) memman_alloc_4k(memman, 256 * 165); - sheet_setbuf(sht_cons, buf_cons, 256, 165, -1); /* 无透明色 */ - make_window8(buf_cons, 256, 165, "console", 0); - make_textbox8(sht_cons, 8, 28, 240, 128, COL8_000000); - task_cons = task_alloc(); - task_cons->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 12; - task_cons->tss.eip = (int) &console_task; - task_cons->tss.es = 1 * 8; - task_cons->tss.cs = 2 * 8; - task_cons->tss.ss = 1 * 8; - task_cons->tss.ds = 1 * 8; - task_cons->tss.fs = 1 * 8; - task_cons->tss.gs = 1 * 8; - *((int *) (task_cons->tss.esp + 4)) = (int) sht_cons; - *((int *) (task_cons->tss.esp + 8)) = memtotal; - task_run(task_cons, 2, 2); /* level=2, priority=2 */ + for (i = 0; i < 2; i++) { + sht_cons[i] = sheet_alloc(shtctl); + buf_cons[i] = (unsigned char *) memman_alloc_4k(memman, 256 * 165); + sheet_setbuf(sht_cons[i], buf_cons[i], 256, 165, -1); /*没有透明色*/ + make_window8(buf_cons[i], 256, 165, "console", 0); + make_textbox8(sht_cons[i], 8, 28, 240, 128, COL8_000000); + task_cons[i] = task_alloc(); + task_cons[i]->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 12; + task_cons[i]->tss.eip = (int) &console_task; + task_cons[i]->tss.es = 1 * 8; + task_cons[i]->tss.cs = 2 * 8; + task_cons[i]->tss.ss = 1 * 8; + task_cons[i]->tss.ds = 1 * 8; + task_cons[i]->tss.fs = 1 * 8; + task_cons[i]->tss.gs = 1 * 8; + *((int *) (task_cons[i]->tss.esp + 4)) = (int) sht_cons[i]; + *((int *) (task_cons[i]->tss.esp + 8)) = memtotal; + task_run(task_cons[i], 2, 2); /* level=2, priority=2 */ + sht_cons[i]->task = task_cons[i]; + sht_cons[i]->flags |= 0x20; /*有光标*/ + } /* sht_win */ sht_win = sheet_alloc(shtctl); @@ -116,16 +120,16 @@ void HariMain(void) my = (binfo->scrny - 28 - 16) / 2; sheet_slide(sht_back, 0, 0); - sheet_slide(sht_cons, 32, 4); + sheet_slide(sht_cons[1], 56, 6); + sheet_slide(sht_cons[0], 8, 2); sheet_slide(sht_win, 64, 56); sheet_slide(sht_mouse, mx, my); sheet_updown(sht_back, 0); - sheet_updown(sht_cons, 1); - sheet_updown(sht_win, 2); - sheet_updown(sht_mouse, 3); + sheet_updown(sht_cons[1], 1); + sheet_updown(sht_cons[0], 2); + sheet_updown(sht_win, 3); + sheet_updown(sht_mouse, 4); key_win = sht_win; - sht_cons->task = task_cons; - sht_cons->flags |= 0x20; /*有光标*/ /*为了避免和键盘当前状态冲突,在一开始先进行设置*/ fifo32_put(&keycmd, KEYCMD_LED); @@ -228,12 +232,12 @@ void HariMain(void) fifo32_put(&keycmd, KEYCMD_LED); fifo32_put(&keycmd, key_leds); } - if (i == 256 + 0x3b && key_shift != 0 && task_cons->tss.ss0 != 0) { /* Shift+F1 */ + if (i == 256 + 0x3b && key_shift != 0 && task_cons[0]->tss.ss0 != 0) { /* Shift+F1 */ cons = (struct CONSOLE *) *((int *) 0x0fec); cons_putstr0(cons, "\nBreak(key) :\n"); - io_cli(); /*不能在改变寄存器值时切换到其他任务*/ - task_cons->tss.eax = (int) &(task_cons->tss.esp0); - task_cons->tss.eip = (int) asm_end_app; + io_cli(); /*强制结束处理时禁止任务切换*/ + task_cons[0]->tss.eax = (int) &(task_cons[0]->tss.esp0); + task_cons[0]->tss.eip = (int) asm_end_app; io_sti(); } if (i == 256 + 0x57 && shtctl->top > 2) { /* F11 */ @@ -297,9 +301,8 @@ void HariMain(void) cons = (struct CONSOLE *) *((int *) 0x0fec); cons_putstr0(cons, "\nBreak(mouse) :\n"); io_cli(); /*强制结束处理中禁止切换任务*/ - task_cons->tss.eax = (int) - &(task_cons->tss.esp0); - task_cons->tss.eip = (int) asm_end_app; + task_cons[0]->tss.eax = (int) &(task_cons[0]->tss.esp0); + task_cons[0]->tss.eip = (int) asm_end_app; io_sti(); } } From c512f3e3913a44f28aaaef12d128e1c675a52a78 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 11:08:20 +0800 Subject: [PATCH 16/83] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E8=A1=8C=E7=AA=97=E5=8F=A3=EF=BC=882=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 25_day/bootpack.h | 2 ++ 25_day/console.c | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/25_day/bootpack.h b/25_day/bootpack.h index bc14ac9..5f6554d 100644 --- a/25_day/bootpack.h +++ b/25_day/bootpack.h @@ -212,6 +212,8 @@ struct TASK { int level, priority; /* 优先级 */ struct FIFO32 fifo; struct TSS32 tss; + struct CONSOLE *cons; + int ds_base; }; struct TASKLEVEL { int running; /*正在运行的任务数量*/ diff --git a/25_day/console.c b/25_day/console.c index 30017c8..1af41a8 100644 --- a/25_day/console.c +++ b/25_day/console.c @@ -16,7 +16,7 @@ void console_task(struct SHEET *sheet, unsigned int memtotal) cons.cur_x = 8; cons.cur_y = 28; cons.cur_c = -1; - *((int *) 0x0fec) = (int) &cons; + task->cons = &cons; fifo32_init(&task->fifo, 128, fifobuf, task); timer = timer_alloc(); @@ -293,7 +293,7 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) datsiz = *((int *) (p + 0x0010)); dathrb = *((int *) (p + 0x0014)); q = (char *) memman_alloc_4k(memman, segsiz); - *((int *) 0xfe8) = (int) q; + task->ds_base = (int) q; set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); set_segmdesc(gdt + 1004, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); for (i = 0; i < datsiz; i++) { @@ -323,9 +323,9 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) { - int ds_base = *((int *) 0xfe8); struct TASK *task = task_now(); - struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec); + int ds_base = task->ds_base; + struct CONSOLE *cons = task->cons; struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); struct SHEET *sht; int *reg = &eax + 1; /* eax后面的地址*/ @@ -435,8 +435,8 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int int *inthandler0c(int *esp) { - struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec); struct TASK *task = task_now(); + struct CONSOLE *cons = task->cons; char s[30]; cons_putstr0(cons, "\nINT 0C :\n Stack Exception.\n"); sprintf(s, "EIP = %08X\n", esp[11]); @@ -446,8 +446,8 @@ int *inthandler0c(int *esp) int *inthandler0d(int *esp) { - struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec); struct TASK *task = task_now(); + struct CONSOLE *cons = task->cons; char s[30]; cons_putstr0(cons, "\nINT 0D :\n General Protected Exception.\n"); sprintf(s, "EIP = %08X\n", esp[11]); From 34fc4eca27c17458024593eb834d1272312d99ad Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 11:18:02 +0800 Subject: [PATCH 17/83] bug fix --- 24_day/console.c | 12 ------------ 25_day/console.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/24_day/console.c b/24_day/console.c index ceb2fc4..ab3f80a 100644 --- a/24_day/console.c +++ b/24_day/console.c @@ -429,18 +429,6 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int timer_settime((struct TIMER *) ebx, eax); } else if (edx == 19) { timer_free((struct TIMER *) ebx); - } else if (edx == 20) { - if (eax == 0) { - i = io_in8(0x61); - io_out8(0x61, i & 0x0d); - } else { - i = 1193180000 / eax; - io_out8(0x43, 0xb6); - io_out8(0x42, i & 0xff); - io_out8(0x42, i >> 8); - i = io_in8(0x61); - io_out8(0x61, (i | 0x03) & 0x0f); - } } return 0; } diff --git a/25_day/console.c b/25_day/console.c index 1af41a8..dc323db 100644 --- a/25_day/console.c +++ b/25_day/console.c @@ -429,6 +429,18 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int timer_settime((struct TIMER *) ebx, eax); } else if (edx == 19) { timer_free((struct TIMER *) ebx); + } else if (edx == 20) { + if (eax == 0) { + i = io_in8(0x61); + io_out8(0x61, i & 0x0d); + } else { + i = 1193180000 / eax; + io_out8(0x43, 0xb6); + io_out8(0x42, i & 0xff); + io_out8(0x42, i >> 8); + i = io_in8(0x61); + io_out8(0x61, (i | 0x03) & 0x0f); + } } return 0; } From d1e4c441491157f1f4d1eb894b31e7d1f7526425 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 11:21:01 +0800 Subject: [PATCH 18/83] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E8=A1=8C=E7=AA=97=E5=8F=A3=EF=BC=883=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 25_day/console.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/25_day/console.c b/25_day/console.c index dc323db..1b58cd6 100644 --- a/25_day/console.c +++ b/25_day/console.c @@ -294,12 +294,12 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) dathrb = *((int *) (p + 0x0014)); q = (char *) memman_alloc_4k(memman, segsiz); task->ds_base = (int) q; - set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); - set_segmdesc(gdt + 1004, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); + set_segmdesc(gdt + task->sel / 8 + 1000, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); + set_segmdesc(gdt + task->sel / 8 + 2000, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); for (i = 0; i < datsiz; i++) { q[esp + i] = p[dathrb + i]; } - start_app(0x1b, 1003 * 8, esp, 1004 * 8, &(task->tss.esp0)); + start_app(0x1b, task->sel + 1000 * 8, esp, task->sel + 2000 * 8, &(task->tss.esp0)); shtctl = (struct SHTCTL *) *((int *) 0x0fe4); for (i = 0; i < MAX_SHEETS; i++) { sht = &(shtctl->sheets0[i]); From 24945ddb181a49e24c5a1ecc8610e4d0ef96575c Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 11:30:45 +0800 Subject: [PATCH 19/83] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E8=A1=8C=E7=AA=97=E5=8F=A3=EF=BC=884=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 25_day/bootpack.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/25_day/bootpack.c b/25_day/bootpack.c index 9d5c075..0b011af 100644 --- a/25_day/bootpack.c +++ b/25_day/bootpack.c @@ -21,7 +21,7 @@ void HariMain(void) struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; unsigned char *buf_back, buf_mouse[256], *buf_win, *buf_cons[2]; struct SHEET *sht_back, *sht_mouse, *sht_win, *sht_cons[2]; - struct TASK *task_a, *task_cons[2]; + struct TASK *task_a, *task_cons[2], *task; struct TIMER *timer; static char keytable0[0x80] = { 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0, 0, @@ -232,13 +232,15 @@ void HariMain(void) fifo32_put(&keycmd, KEYCMD_LED); fifo32_put(&keycmd, key_leds); } - if (i == 256 + 0x3b && key_shift != 0 && task_cons[0]->tss.ss0 != 0) { /* Shift+F1 */ - cons = (struct CONSOLE *) *((int *) 0x0fec); - cons_putstr0(cons, "\nBreak(key) :\n"); - io_cli(); /*强制结束处理时禁止任务切换*/ - task_cons[0]->tss.eax = (int) &(task_cons[0]->tss.esp0); - task_cons[0]->tss.eip = (int) asm_end_app; - io_sti(); + if (i == 256 + 0x3b && key_shift != 0) { + task = key_win->task; + if (task != 0 && task->tss.ss0 != 0) { /* Shift+F1 */ + cons_putstr0(cons, "\nBreak(key) :\n"); + io_cli(); /*强制结束处理时禁止任务切换*/ + task->tss.eax = (int) &(task->tss.esp0); + task->tss.eip = (int) asm_end_app; + io_sti(); + } } if (i == 256 + 0x57 && shtctl->top > 2) { /* F11 */ sheet_updown(shtctl->sheets[1], shtctl->top - 1); @@ -298,11 +300,11 @@ void HariMain(void) if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <=y && y < 19) { /*点击“×”按钮*/ if ((sht->flags & 0x10) != 0) { /*该窗口是否为应用程序窗口?*/ - cons = (struct CONSOLE *) *((int *) 0x0fec); + task = sht->task; cons_putstr0(cons, "\nBreak(mouse) :\n"); - io_cli(); /*强制结束处理中禁止切换任务*/ - task_cons[0]->tss.eax = (int) &(task_cons[0]->tss.esp0); - task_cons[0]->tss.eip = (int) asm_end_app; + io_cli(); /*强制结束处理时禁止任务切换*/ + task->tss.eax = (int) &(task->tss.esp0);/*到此结束*/ + task->tss.eip = (int) asm_end_app; io_sti(); } } From 95542da7f7204dd529dd4c6a71815e7056148aba Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 11:47:29 +0800 Subject: [PATCH 20/83] =?UTF-8?q?=E5=8F=98=E5=BE=97=E6=9B=B4=E5=83=8F?= =?UTF-8?q?=E7=9C=9F=E6=AD=A3=E7=9A=84=E6=93=8D=E4=BD=9C=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=EF=BC=881=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 25_day/bootpack.c | 112 +++++++++------------------------------------- 1 file changed, 21 insertions(+), 91 deletions(-) diff --git a/25_day/bootpack.c b/25_day/bootpack.c index 0b011af..95e569d 100644 --- a/25_day/bootpack.c +++ b/25_day/bootpack.c @@ -5,8 +5,8 @@ #define KEYCMD_LED 0xed -int keywin_off(struct SHEET *key_win, struct SHEET *sht_win, int cur_c, int cur_x); -int keywin_on(struct SHEET *key_win, struct SHEET *sht_win, int cur_c); +void keywin_off(struct SHEET *key_win); +void keywin_on(struct SHEET *key_win); void HariMain(void) { @@ -15,14 +15,13 @@ void HariMain(void) char s[40]; struct FIFO32 fifo, keycmd; int fifobuf[128], keycmd_buf[32]; - int mx, my, i, cursor_x, cursor_c; + int mx, my, i; unsigned int memtotal; struct MOUSE_DEC mdec; struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; - unsigned char *buf_back, buf_mouse[256], *buf_win, *buf_cons[2]; + unsigned char *buf_back, buf_mouse[256], *buf_cons[2]; struct SHEET *sht_back, *sht_mouse, *sht_win, *sht_cons[2]; struct TASK *task_a, *task_cons[2], *task; - struct TIMER *timer; static char keytable0[0x80] = { 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0, 0, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0, 0, 'A', 'S', @@ -100,18 +99,6 @@ void HariMain(void) sht_cons[i]->flags |= 0x20; /*有光标*/ } - /* sht_win */ - sht_win = sheet_alloc(shtctl); - buf_win = (unsigned char *) memman_alloc_4k(memman, 160 * 52); - sheet_setbuf(sht_win, buf_win, 144, 52, -1); /* 无透明色 */ - make_window8(buf_win, 144, 52, "task_a", 1); - make_textbox8(sht_win, 8, 28, 128, 16, COL8_FFFFFF); - cursor_x = 8; - cursor_c = COL8_FFFFFF; - timer = timer_alloc(); - timer_init(timer, &fifo, 1); - timer_settime(timer, 50); - /* sht_mouse */ sht_mouse = sheet_alloc(shtctl); sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99); @@ -127,9 +114,9 @@ void HariMain(void) sheet_updown(sht_back, 0); sheet_updown(sht_cons[1], 1); sheet_updown(sht_cons[0], 2); - sheet_updown(sht_win, 3); - sheet_updown(sht_mouse, 4); - key_win = sht_win; + sheet_updown(sht_mouse, 3); + key_win = sht_cons[0]; + keywin_on(key_win); /*为了避免和键盘当前状态冲突,在一开始先进行设置*/ fifo32_put(&keycmd, KEYCMD_LED); @@ -151,7 +138,6 @@ void HariMain(void) io_sti(); if (key_win->flags == 0) { /*输入窗口被关闭*/ key_win = shtctl->sheets[shtctl->top - 1]; - cursor_c = keywin_on(key_win, sht_win, cursor_c); } if (256 <= i && i <= 511) { /* 键盘数据*/ if (i < 0x80 + 256) { /*将按键编码转换为字符编码*/ @@ -168,42 +154,17 @@ void HariMain(void) s[0] += 0x20; /*将大写字母转换为小写字母*/ } } - if (s[0] != 0) { /*一般字符*/ - if (key_win == sht_win) { /*发送给任务A */ - if (cursor_x < 128) { - /*显示一个字符之后将光标后移一位*/ - s[1] = 0; - putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1); - cursor_x += 8; - } - } else { /*发送给命令行窗口*/ - fifo32_put(&key_win->task->fifo, s[0] + 256); - } - } - if (i == 256 + 0x0e) { /* 退格键 */ - if (key_win == sht_win) { /*发送给任务A */ - if (cursor_x > 8) { - /*用空白擦除光标后将光标前移一位*/ - putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1); - cursor_x -= 8; - } - } else { /*发送给命令行窗口*/ - fifo32_put(&key_win->task->fifo, 8 + 256); - } - } - if (i == 256 + 0x1c) { /*回车键*/ - if (key_win != sht_win) { /*发送至命令行窗口*/ - fifo32_put(&key_win->task->fifo, 10 + 256); - } + if (s[0] != 0) { /*一般字符、退格键、回车键*/ + fifo32_put(&key_win->task->fifo, s[0] + 256); } if (i == 256 + 0x0f) { /* Tab键 */ - cursor_c = keywin_off(key_win, sht_win, cursor_c, cursor_x); + keywin_off(key_win); j = key_win->height - 1; if (j == 0) { j = shtctl->top - 1; } key_win = shtctl->sheets[j]; - cursor_c = keywin_on(key_win, sht_win, cursor_c); + keywin_on(key_win); } if (i == 256 + 0x2a) { /*左Shift ON */ key_shift |= 1; @@ -252,11 +213,6 @@ void HariMain(void) wait_KBC_sendready(); io_out8(PORT_KEYDAT, keycmd_wait); } - /*重新显示光标*/ - if (cursor_c >= 0) { - boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); - } - sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44); } else if (512 <= i && i <= 767) { /* 鼠标数据*/ if (mouse_decode(&mdec, i - 512) != 0) { /* 已经收集了3字节的数据,移动光标 */ @@ -289,9 +245,9 @@ void HariMain(void) if (sht->buf[y * sht->bxsize + x] != sht->col_inv) { sheet_updown(sht, shtctl->top - 1); if (sht != key_win) { - cursor_c = keywin_off(key_win, sht_win, cursor_c, cursor_x); + keywin_off(key_win); key_win = sht; - cursor_c = keywin_on(key_win, sht_win, cursor_c);/*到此结束*/ + keywin_on(key_win); } if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) { mmx = mx; /*进入窗口移动模式*/ @@ -326,51 +282,25 @@ void HariMain(void) } } - } else if (i <= 1) { /* 光标用定时器*/ - if (i != 0) { - timer_init(timer, &fifo, 0); /* 下面设定0 */ - if (cursor_c >= 0) { - cursor_c = COL8_000000; - } - } else { - timer_init(timer, &fifo, 1); /* 下面设定1 */ - if (cursor_c >= 0) { - cursor_c = COL8_FFFFFF; - } - } - timer_settime(timer, 50); - if (cursor_c >= 0) { - boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); - sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44); - } } } } } -int keywin_off(struct SHEET *key_win, struct SHEET *sht_win, int cur_c, int cur_x) +void keywin_off(struct SHEET *key_win) { change_wtitle8(key_win, 0); - if (key_win == sht_win) { - cur_c = -1; /*删除光标*/ - boxfill8(sht_win->buf, sht_win->bxsize, COL8_FFFFFF, cur_x, 28, cur_x + 7, 43); - } else { - if ((key_win->flags & 0x20) != 0) { - fifo32_put(&key_win->task->fifo, 3); /*命令行窗口光标OFF */ - } + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 3); /*命令行窗口光标OFF */ } - return cur_c; + return; } -int keywin_on(struct SHEET *key_win, struct SHEET *sht_win, int cur_c) +void keywin_on(struct SHEET *key_win) { change_wtitle8(key_win, 1); - if (key_win == sht_win) { - cur_c = COL8_000000; /*显示光标*/ - } else { - if ((key_win->flags & 0x20) != 0) { - fifo32_put(&key_win->task->fifo, 2); /*命令行窗口光标ON */ - } + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 2); /*命令行窗口光标ON */ } - return cur_c; + return; } From 5bc0adee61f7bf4593aad9410d10809b88409170 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 11:54:11 +0800 Subject: [PATCH 21/83] =?UTF-8?q?=E5=8F=98=E5=BE=97=E6=9B=B4=E5=83=8F?= =?UTF-8?q?=E7=9C=9F=E6=AD=A3=E7=9A=84=E6=93=8D=E4=BD=9C=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=EF=BC=882=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 25_day/bootpack.c | 5 +++-- 25_day/console.c | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/25_day/bootpack.c b/25_day/bootpack.c index 95e569d..8a2a773 100644 --- a/25_day/bootpack.c +++ b/25_day/bootpack.c @@ -14,7 +14,7 @@ void HariMain(void) struct SHTCTL *shtctl; char s[40]; struct FIFO32 fifo, keycmd; - int fifobuf[128], keycmd_buf[32]; + int fifobuf[128], keycmd_buf[32], *cons_fifo[2]; int mx, my, i; unsigned int memtotal; struct MOUSE_DEC mdec; @@ -97,6 +97,8 @@ void HariMain(void) task_run(task_cons[i], 2, 2); /* level=2, priority=2 */ sht_cons[i]->task = task_cons[i]; sht_cons[i]->flags |= 0x20; /*有光标*/ + cons_fifo[i] = (int *) memman_alloc_4k(memman, 128 * 4); + fifo32_init(&task_cons[i]->fifo, 128, cons_fifo[i], task_cons[i]); } /* sht_mouse */ @@ -116,7 +118,6 @@ void HariMain(void) sheet_updown(sht_cons[0], 2); sheet_updown(sht_mouse, 3); key_win = sht_cons[0]; - keywin_on(key_win); /*为了避免和键盘当前状态冲突,在一开始先进行设置*/ fifo32_put(&keycmd, KEYCMD_LED); diff --git a/25_day/console.c b/25_day/console.c index 1b58cd6..2cfb82a 100644 --- a/25_day/console.c +++ b/25_day/console.c @@ -9,7 +9,7 @@ void console_task(struct SHEET *sheet, unsigned int memtotal) struct TIMER *timer; struct TASK *task = task_now(); struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; - int i, fifobuf[128], *fat = (int *) memman_alloc_4k(memman, 4 * 2880); + int i, *fat = (int *) memman_alloc_4k(memman, 4 * 2880); struct CONSOLE cons; char cmdline[30]; cons.sht = sheet; @@ -18,7 +18,6 @@ void console_task(struct SHEET *sheet, unsigned int memtotal) cons.cur_c = -1; task->cons = &cons; - fifo32_init(&task->fifo, 128, fifobuf, task); timer = timer_alloc(); timer_init(timer, &task->fifo, 1); timer_settime(timer, 50); From a789f578a8e575fcee0e153d26a5b3dd85e3237f Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 12:09:07 +0800 Subject: [PATCH 22/83] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=95=B4=E7=90=86?= =?UTF-8?q?=EF=BC=8C=E9=94=99=E8=AF=AF=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 25_day/bootpack.c | 50 ++++++++++++++++++++++----------------------- 25_day/bootpack.h | 25 ++++++++++++----------- 25_day/console.c | 48 +++++++++++++++++++++---------------------- 25_day/dsctbl.c | 3 +-- 25_day/file.c | 10 ++++----- 25_day/int.c | 11 ---------- 25_day/mtask.c | 35 ++++++++++++++++--------------- 25_day/naskfunc.nas | 34 ++++++++---------------------- 8 files changed, 94 insertions(+), 122 deletions(-) diff --git a/25_day/bootpack.c b/25_day/bootpack.c index 8a2a773..d2aa307 100644 --- a/25_day/bootpack.c +++ b/25_day/bootpack.c @@ -14,17 +14,17 @@ void HariMain(void) struct SHTCTL *shtctl; char s[40]; struct FIFO32 fifo, keycmd; - int fifobuf[128], keycmd_buf[32], *cons_fifo[2]; + int fifobuf[128], keycmd_buf[32], *cons_fifo[2]; int mx, my, i; unsigned int memtotal; struct MOUSE_DEC mdec; struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; unsigned char *buf_back, buf_mouse[256], *buf_cons[2]; - struct SHEET *sht_back, *sht_mouse, *sht_win, *sht_cons[2]; + struct SHEET *sht_back, *sht_mouse, *sht_cons[2]; struct TASK *task_a, *task_cons[2], *task; static char keytable0[0x80] = { - 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0, 0, - 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0, 0, 'A', 'S', + 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0x08, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0x0a, 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', @@ -33,8 +33,8 @@ void HariMain(void) 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0 }; static char keytable1[0x80] = { - 0, 0, '!', 0x22, '#', '$', '%', '&', 0x27, '(', ')', '~', '=', '~', 0, 0, - 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0, 0, 'A', 'S', + 0, 0, '!', 0x22, '#', '$', '%', '&', 0x27, '(', ')', '~', '=', '~', 0x08, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0x0a, 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', '+', '*', 0, 0, '}', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', @@ -43,7 +43,6 @@ void HariMain(void) 0, 0, 0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, '|', 0, 0 }; int key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; - struct CONSOLE *cons; int j, x, y, mmx = -1, mmy = -1; struct SHEET *sht = 0, *key_win; @@ -109,15 +108,15 @@ void HariMain(void) my = (binfo->scrny - 28 - 16) / 2; sheet_slide(sht_back, 0, 0); - sheet_slide(sht_cons[1], 56, 6); - sheet_slide(sht_cons[0], 8, 2); - sheet_slide(sht_win, 64, 56); + sheet_slide(sht_cons[1], 56, 6); + sheet_slide(sht_cons[0], 8, 2); sheet_slide(sht_mouse, mx, my); - sheet_updown(sht_back, 0); - sheet_updown(sht_cons[1], 1); - sheet_updown(sht_cons[0], 2); - sheet_updown(sht_mouse, 3); + sheet_updown(sht_back, 0); + sheet_updown(sht_cons[1], 1); + sheet_updown(sht_cons[0], 2); + sheet_updown(sht_mouse, 3); key_win = sht_cons[0]; + keywin_on(key_win); /*为了避免和键盘当前状态冲突,在一开始先进行设置*/ fifo32_put(&keycmd, KEYCMD_LED); @@ -125,7 +124,7 @@ void HariMain(void) for (;;) { if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0) { - /*如果存在向键盘控制器发送的数据,则发送它 */ + /* �L�[�{�[�h�R���g���[���ɑ���f�[�^������΁A���� */ keycmd_wait = fifo32_get(&keycmd); wait_KBC_sendready(); io_out8(PORT_KEYDAT, keycmd_wait); @@ -139,6 +138,7 @@ void HariMain(void) io_sti(); if (key_win->flags == 0) { /*输入窗口被关闭*/ key_win = shtctl->sheets[shtctl->top - 1]; + keywin_on(key_win); } if (256 <= i && i <= 511) { /* 键盘数据*/ if (i < 0x80 + 256) { /*将按键编码转换为字符编码*/ @@ -151,7 +151,8 @@ void HariMain(void) s[0] = 0; } if ('A' <= s[0] && s[0] <= 'Z') { /*当输入字符为英文字母时*/ - if (((key_leds & 4) == 0 && key_shift == 0) ||((key_leds & 4) != 0 && key_shift != 0)) { + if (((key_leds & 4) == 0 && key_shift == 0) || + ((key_leds & 4) != 0 && key_shift != 0)) { s[0] += 0x20; /*将大写字母转换为小写字母*/ } } @@ -196,15 +197,15 @@ void HariMain(void) } if (i == 256 + 0x3b && key_shift != 0) { task = key_win->task; - if (task != 0 && task->tss.ss0 != 0) { /* Shift+F1 */ - cons_putstr0(cons, "\nBreak(key) :\n"); + if (task != 0 && task->tss.ss0 != 0) { /* Shift+F1 */ + cons_putstr0(task->cons, "\nBreak(key) :\n"); io_cli(); /*强制结束处理时禁止任务切换*/ task->tss.eax = (int) &(task->tss.esp0); task->tss.eip = (int) asm_end_app; io_sti(); } } - if (i == 256 + 0x57 && shtctl->top > 2) { /* F11 */ + if (i == 256 + 0x57) { /* F11 */ sheet_updown(shtctl->sheets[1], shtctl->top - 1); } if (i == 256 + 0xfa) { /*键盘成功接收到数据*/ @@ -231,9 +232,7 @@ void HariMain(void) if (my > binfo->scrny - 1) { my = binfo->scrny - 1; } - sheet_slide(sht_mouse, mx, my);/* 包含sheet_refresh含sheet_refresh */ - if ((mdec.btn & 0x01) != 0) { /* 按下左键 */ if (mmx < 0) { /*如果处于通常模式*/ @@ -254,13 +253,13 @@ void HariMain(void) mmx = mx; /*进入窗口移动模式*/ mmy = my; } - if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <=y && y < 19) { + if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <= y && y < 19) { /*点击“×”按钮*/ if ((sht->flags & 0x10) != 0) { /*该窗口是否为应用程序窗口?*/ task = sht->task; - cons_putstr0(cons, "\nBreak(mouse) :\n"); + cons_putstr0(task->cons, "\nBreak(mouse) :\n"); io_cli(); /*强制结束处理时禁止任务切换*/ - task->tss.eax = (int) &(task->tss.esp0);/*到此结束*/ + task->tss.eax = (int) &(task->tss.esp0); task->tss.eip = (int) asm_end_app; io_sti(); } @@ -279,9 +278,8 @@ void HariMain(void) } } else { /*没有按下左键*/ - mmx = -1; /*返回通常模式*/ + mmx = -1; /*返回通常模式*/ } - } } } diff --git a/25_day/bootpack.h b/25_day/bootpack.h index 5f6554d..9975f09 100644 --- a/25_day/bootpack.h +++ b/25_day/bootpack.h @@ -28,7 +28,6 @@ void asm_inthandler0c(void); void asm_inthandler0d(void); void asm_inthandler20(void); void asm_inthandler21(void); -void asm_inthandler27(void); void asm_inthandler2c(void); unsigned int memtest_sub(unsigned int start, unsigned int end); void farjmp(int eip, int cs); @@ -102,7 +101,6 @@ void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar); /* int.c */ void init_pic(void); -void inthandler27(int *esp); #define PIC0_ICW1 0x0020 #define PIC0_OCW2 0x0020 #define PIC0_IMR 0x0021 @@ -133,12 +131,12 @@ void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec); int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat); /* memory.c */ -#define MEMMAN_FREES 4090 /* 大约是32KB*/ +#define MEMMAN_FREES 4090 /* ����Ŗ�32KB */ #define MEMMAN_ADDR 0x003c0000 -struct FREEINFO { /* 可用信息 */ +struct FREEINFO { /* ������� */ unsigned int addr, size; }; -struct MEMMAN { /* 内存管理 */ +struct MEMMAN { /* �������Ǘ� */ int frees, maxfrees, lostsize, losts; struct FREEINFO free[MEMMAN_FREES]; }; @@ -177,7 +175,7 @@ void sheet_free(struct SHEET *sht); struct TIMER { struct TIMER *next; unsigned int timeout; - char flags, flags2; + char flags, flags2; struct FIFO32 *fifo; int data; }; @@ -199,8 +197,8 @@ void timer_cancelall(struct FIFO32 *fifo); /* mtask.c */ #define MAX_TASKS 1000 /*最大任务数量*/ #define TASK_GDT0 3 /*定义从GDT的几号开始分配给TSS */ -#define MAX_TASKS_LV 100 -#define MAX_TASKLEVELS 10 +#define MAX_TASKS_LV 100 +#define MAX_TASKLEVELS 10 struct TSS32 { int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3; int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi; @@ -227,6 +225,7 @@ struct TASKCTL { struct TASK tasks0[MAX_TASKS]; }; extern struct TIMER *task_timer; +struct TASK *task_now(void); struct TASK *task_init(struct MEMMAN *memman); struct TASK *task_alloc(void); void task_run(struct TASK *task, int level, int priority); @@ -246,20 +245,21 @@ struct CONSOLE { int cur_x, cur_y, cur_c; struct TIMER *timer; }; -void console_task(struct SHEET *sheet, unsigned int memtotal); +void console_task(struct SHEET *sheet, int memtotal); void cons_putchar(struct CONSOLE *cons, int chr, char move); void cons_newline(struct CONSOLE *cons); void cons_putstr0(struct CONSOLE *cons, char *s); void cons_putstr1(struct CONSOLE *cons, char *s, int l); -void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, unsigned int memtotal); -void cmd_mem(struct CONSOLE *cons, unsigned int memtotal); +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal); +void cmd_mem(struct CONSOLE *cons, int memtotal); void cmd_cls(struct CONSOLE *cons); void cmd_dir(struct CONSOLE *cons); void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline); int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline); int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax); -int *inthandler0c(int *esp); int *inthandler0d(int *esp); +int *inthandler0c(int *esp); +void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col); /* file.c */ struct FILEINFO { @@ -271,3 +271,4 @@ struct FILEINFO { void file_readfat(int *fat, unsigned char *img); void file_loadfile(int clustno, int size, char *buf, int *fat, char *img); struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max); + diff --git a/25_day/console.c b/25_day/console.c index 2cfb82a..7df9bea 100644 --- a/25_day/console.c +++ b/25_day/console.c @@ -4,48 +4,48 @@ #include #include -void console_task(struct SHEET *sheet, unsigned int memtotal) +void console_task(struct SHEET *sheet, int memtotal) { - struct TIMER *timer; struct TASK *task = task_now(); struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; int i, *fat = (int *) memman_alloc_4k(memman, 4 * 2880); struct CONSOLE cons; char cmdline[30]; cons.sht = sheet; - cons.cur_x = 8; + cons.cur_x = 8; cons.cur_y = 28; cons.cur_c = -1; task->cons = &cons; - timer = timer_alloc(); - timer_init(timer, &task->fifo, 1); - timer_settime(timer, 50); - file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); + cons.timer = timer_alloc(); + timer_init(cons.timer, &task->fifo, 1); + timer_settime(cons.timer, 50); + file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); /*显示提示符*/ cons_putchar(&cons, '>', 1); + for (;;) { io_cli(); if (fifo32_status(&task->fifo) == 0) { - task_sleep(task); + task_sleep(task); io_sti(); } else { i = fifo32_get(&task->fifo); io_sti(); if (i <= 1) { /*光标用定时器*/ if (i != 0) { - timer_init(timer, &task->fifo, 0); /*下次置0 */ + timer_init(cons.timer, &task->fifo, 0); /*下次置0 */ if (cons.cur_c >= 0) { cons.cur_c = COL8_FFFFFF; } } else { - timer_init(timer, &task->fifo, 1); /*下次置1 */ + timer_init(cons.timer, &task->fifo, 1); /*下次置1 */ if (cons.cur_c >= 0) { cons.cur_c = COL8_000000; } } - timer_settime(timer, 50); + timer_settime(cons.timer, 50); } if (i == 2) { /*光标ON */ cons.cur_c = COL8_FFFFFF; @@ -163,7 +163,7 @@ void cons_putstr1(struct CONSOLE *cons, char *s, int l) return; } -void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, unsigned int memtotal) +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) { if (strcmp(cmdline, "mem") == 0) { cmd_mem(cons, memtotal); @@ -182,11 +182,11 @@ void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, unsigned int mem return; } -void cmd_mem(struct CONSOLE *cons, unsigned int memtotal) +void cmd_mem(struct CONSOLE *cons, int memtotal) { struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; char s[60]; - sprintf(s, "total %dMB\nfree %dKB\n\n", memtotal / (1024 * 1024), memman_total(memman) / 1024); + sprintf(s, "total %dMB\nfree %dKB\n\n", memtotal / (1024 * 1024), memman_total(memman) / 1024); cons_putstr0(cons, s); return; } @@ -216,7 +216,7 @@ void cmd_dir(struct CONSOLE *cons) } if (finfo[i].name[0] != 0xe5) { if ((finfo[i].type & 0x18) == 0) { - sprintf(s, "filename.ext %7d\n", finfo[i].size); + sprintf(s, "filename.ext %7d\n", finfo[i].size); for (j = 0; j < 8; j++) { s[j] = finfo[i].name[j]; } @@ -241,7 +241,7 @@ void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline) p = (char *) memman_alloc_4k(memman, finfo->size); file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); cons_putstr1(cons, p, finfo->size); - memman_free_4k(memman, (int) p, finfo->size); + memman_free_4k(memman, (int) p, finfo->size); } else { /*没有找到文件的情况*/ cons_putstr0(cons, "File not found.\n"); @@ -272,9 +272,9 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) /*寻找文件 */ finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); - if (finfo == 0 && name[i -1]!= '.') { + if (finfo == 0 && name[i - 1] != '.') { /*由于找不到文件,故在文件名后面加上“.hrb”后重新寻找*/ - name[i ] = '.'; + name[i ] = '.'; name[i + 1] = 'H'; name[i + 2] = 'R'; name[i + 3] = 'B'; @@ -294,7 +294,7 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) q = (char *) memman_alloc_4k(memman, segsiz); task->ds_base = (int) q; set_segmdesc(gdt + task->sel / 8 + 1000, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); - set_segmdesc(gdt + task->sel / 8 + 2000, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); + set_segmdesc(gdt + task->sel / 8 + 2000, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); for (i = 0; i < datsiz; i++) { q[esp + i] = p[dathrb + i]; } @@ -329,8 +329,8 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int struct SHEET *sht; int *reg = &eax + 1; /* eax后面的地址*/ /*强行改写通过PUSHAD保存的值*/ - /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */ - /* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ + /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */ + /* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ int i; if (edx == 1) { @@ -349,7 +349,7 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0); sheet_slide(sht, (shtctl->xsize - esi) / 2, (shtctl->ysize - edi) / 2); sheet_updown(sht, shtctl->top); /*将窗口图层高度指定为当前鼠标所在图层的高度,鼠标移到上层*/ - reg[7] = (int) sht; + reg[7] = (int) sht; } else if (edx == 6) { sht = (struct SHEET *) (ebx & 0xfffffffe); putfonts8_asc(sht->buf, sht->bxsize, esi, edi, eax, (char *) ebp + ds_base); @@ -419,7 +419,7 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int return 0; } } - } else if (edx == 16) { + } else if (edx == 16) { reg[7] = (int) timer_alloc(); ((struct TIMER *) reg[7])->flags2 = 1; /*允许自动取消*/ } else if (edx == 17) { @@ -428,7 +428,7 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int timer_settime((struct TIMER *) ebx, eax); } else if (edx == 19) { timer_free((struct TIMER *) ebx); - } else if (edx == 20) { + } else if (edx == 20) { if (eax == 0) { i = io_in8(0x61); io_out8(0x61, i & 0x0d); diff --git a/25_day/dsctbl.c b/25_day/dsctbl.c index 05bfe89..9ff2c67 100644 --- a/25_day/dsctbl.c +++ b/25_day/dsctbl.c @@ -27,9 +27,8 @@ void init_gdtidt(void) set_gatedesc(idt + 0x0d, (int) asm_inthandler0d, 2 * 8, AR_INTGATE32); set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32); set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32); - set_gatedesc(idt + 0x27, (int) asm_inthandler27, 2 * 8, AR_INTGATE32); set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32); - set_gatedesc(idt + 0x40, (int) asm_hrb_api, 2 * 8, AR_INTGATE32 + 0x60); + set_gatedesc(idt + 0x40, (int) asm_hrb_api, 2 * 8, AR_INTGATE32 + 0x60); return; } diff --git a/25_day/file.c b/25_day/file.c index c289350..bf9d063 100644 --- a/25_day/file.c +++ b/25_day/file.c @@ -7,7 +7,7 @@ void file_readfat(int *fat, unsigned char *img) { int i, j = 0; for (i = 0; i < 2880; i += 2) { - fat[i + 0] = (img[j + 0] | img[j + 1] << 8) & 0xfff; + fat[i + 0] = (img[j + 0] | img[j + 1] << 8) & 0xfff; fat[i + 1] = (img[j + 1] >> 4 | img[j + 2] << 4) & 0xfff; j += 3; } @@ -51,12 +51,12 @@ struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max) if ('a' <= s[j] && s[j] <= 'z') { /*将小写字母转换为大写字母*/ s[j] -= 0x20; - } + } j++; } } for (i = 0; i < max; ) { - if (finfo[i].name[0] == 0x00) { + if (finfo->name[0] == 0x00) { break; } if ((finfo[i].type & 0x18) == 0) { @@ -67,8 +67,8 @@ struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max) } return finfo + i; /*找到文件*/ } - next: - i++; +next: + i++; } return 0; /*没有找到*/ } diff --git a/25_day/int.c b/25_day/int.c index c717372..54c4c7a 100644 --- a/25_day/int.c +++ b/25_day/int.c @@ -24,14 +24,3 @@ void init_pic(void) return; } - -void inthandler27(int *esp) -/* PIC0中断的不完整策略 */ -/* 这个中断在Athlon64X2上通过芯片组提供的便利,只需执行一次 */ -/* 这个中断只是接收,不执行任何操作 */ -/* 为什么不处理? - → 因为这个中断可能是电气噪声引发的、只是处理一些重要的情况。*/ -{ - io_out8(PIC0_OCW2, 0x67); /* 通知PIC的IRQ-07(参考7-1) */ - return; -} diff --git a/25_day/mtask.c b/25_day/mtask.c index b518641..b91869d 100644 --- a/25_day/mtask.c +++ b/25_day/mtask.c @@ -163,6 +163,24 @@ void task_run(struct TASK *task, int level, int priority) return; } +void task_sleep(struct TASK *task) +{ + struct TASK *now_task; + if (task->flags == 2) { + /*如果处于活动状态*/ + now_task = task_now(); + task_remove(task); /*执行此语句的话flags将变为1 */ + if (task == now_task) { + /*如果是让自己休眠,则需要进行任务切换*/ + task_switchsub(); + now_task = task_now(); /*在设定后获取当前任务的值*/ + farjmp(0, now_task->sel); + } + } + return; +} + + void task_switch(void) { struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; @@ -182,20 +200,3 @@ void task_switch(void) } return; } - -void task_sleep(struct TASK *task) -{ - struct TASK *now_task; - if (task->flags == 2) { - /*如果处于活动状态*/ - now_task = task_now(); - task_remove(task); /*执行此语句的话flags将变为1 */ - if (task == now_task) { - /*如果是让自己休眠,则需要进行任务切换*/ - task_switchsub(); - now_task = task_now(); /*在设定后获取当前任务的值*/ - farjmp(0, now_task->sel); - } - } - return; -} diff --git a/25_day/naskfunc.nas b/25_day/naskfunc.nas index d32a472..a45775d 100644 --- a/25_day/naskfunc.nas +++ b/25_day/naskfunc.nas @@ -14,14 +14,14 @@ GLOBAL _load_cr0, _store_cr0 GLOBAL _load_tr GLOBAL _asm_inthandler20, _asm_inthandler21 - GLOBAL _asm_inthandler27, _asm_inthandler2c - GLOBAL _asm_inthandler0c, _asm_inthandler0d - GLOBAL _asm_end_app, _memtest_sub + GLOBAL _asm_inthandler2c, _asm_inthandler0c + GLOBAL _asm_inthandler0d, _asm_end_app + GLOBAL _memtest_sub GLOBAL _farjmp, _farcall GLOBAL _asm_hrb_api, _start_app EXTERN _inthandler20, _inthandler21 - EXTERN _inthandler27, _inthandler2c - EXTERN _inthandler0c, _inthandler0d + EXTERN _inthandler2c, _inthandler0d + EXTERN _inthandler0c EXTERN _hrb_api [SECTION .text] @@ -79,14 +79,14 @@ _io_out32: ; void io_out32(int port, int data); RET _io_load_eflags: ; int io_load_eflags(void); - PUSHFD ; PUSH EFLAGS + PUSHFD ; PUSH EFLAGS POP EAX RET _io_store_eflags: ; void io_store_eflags(int eflags); MOV EAX,[ESP+4] PUSH EAX - POPFD ; POP EFLAGS + POPFD ; POP EFLAGS RET _load_gdtr: ; void load_gdtr(int limit, int addr); @@ -146,22 +146,6 @@ _asm_inthandler21: POP ES IRETD -_asm_inthandler27: - PUSH ES - PUSH DS - PUSHAD - MOV EAX,ESP - PUSH EAX - MOV AX,SS - MOV DS,AX - MOV ES,AX - CALL _inthandler27 - POP EAX - POPAD - POP DS - POP ES - IRETD - _asm_inthandler2c: PUSH ES PUSH DS @@ -278,8 +262,8 @@ _asm_hrb_api: IRETD _asm_end_app: ; EAX为tss.esp0的地址 - MOV ESP,[EAX] - MOV DWORD [EAX+4],0 + MOV ESP,[EAX] + MOV DWORD [EAX+4],0 POPAD RET ; 返回cmd_app From b2dc361194ed59ccf7adb88b74a2043fd449caba Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 13 May 2016 12:12:24 +0800 Subject: [PATCH 23/83] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E5=85=B3?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 25_day/Makefile | 22 +--------------------- 25_day/beepup.c | 22 ---------------------- 25_day/bug2.c | 3 --- 25_day/bug3.c | 9 --------- 4 files changed, 1 insertion(+), 55 deletions(-) delete mode 100644 25_day/beepup.c delete mode 100644 25_day/bug2.c delete mode 100644 25_day/bug3.c diff --git a/25_day/Makefile b/25_day/Makefile index a53ff0f..8714cad 100644 --- a/25_day/Makefile +++ b/25_day/Makefile @@ -80,18 +80,6 @@ hello5.bim : hello5.obj Makefile hello5.hrb : hello5.bim Makefile $(BIM2HRB) hello5.bim hello5.hrb 0 -bug2.bim : bug2.obj Makefile - $(OBJ2BIM) @$(RULEFILE) out:bug2.bim map:bug2.map bug2.obj - -bug2.hrb : bug2.bim Makefile - $(BIM2HRB) bug2.bim bug2.hrb 0 - -bug3.bim : bug3.obj Makefile - $(OBJ2BIM) @$(RULEFILE) out:bug3.bim map:bug3.map bug3.obj a_nask.obj - -bug3.hrb : bug3.bim Makefile - $(BIM2HRB) bug3.bim bug3.hrb 0 - winhelo.bim : winhelo.obj a_nask.obj Makefile $(OBJ2BIM) @$(RULEFILE) out:winhelo.bim stack:1k map:winhelo.map \ winhelo.obj a_nask.obj @@ -162,13 +150,6 @@ beepdown.bim : beepdown.obj a_nask.obj Makefile beepdown.hrb : beepdown.bim Makefile $(BIM2HRB) beepdown.bim beepdown.hrb 40k -beepup.bim : beepup.obj a_nask.obj Makefile - $(OBJ2BIM) @$(RULEFILE) out:beepup.bim stack:1k map:beepup.map \ - beepup.obj a_nask.obj - -beepup.hrb : beepup.bim Makefile - $(BIM2HRB) beepup.bim beepup.hrb 40k - color.bim : color.obj a_nask.obj Makefile $(OBJ2BIM) @$(RULEFILE) out:color.bim stack:1k map:color.map \ color.obj a_nask.obj @@ -186,7 +167,7 @@ color2.hrb : color2.bim Makefile haribote.img : ipl10.bin haribote.sys Makefile \ hello.hrb hello2.hrb a.hrb hello3.hrb hello4.hrb hello5.hrb \ winhelo.hrb winhelo2.hrb winhelo3.hrb star1.hrb stars.hrb stars2.hrb \ - lines.hrb walk.hrb noodle.hrb beepdown.hrb beepup.hrb color.hrb color2.hrb + lines.hrb walk.hrb noodle.hrb beepdown.hrb color.hrb color2.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:ipl10.bin len:512 from:0 to:0 \ copy from:haribote.sys to:@: \ @@ -208,7 +189,6 @@ haribote.img : ipl10.bin haribote.sys Makefile \ copy from:walk.hrb to:@: \ copy from:noodle.hrb to:@: \ copy from:beepdown.hrb to:@: \ - copy from:beepup.hrb to:@: \ copy from:color.hrb to:@: \ copy from:color2.hrb to:@: \ imgout:haribote.img diff --git a/25_day/beepup.c b/25_day/beepup.c deleted file mode 100644 index d14ccb6..0000000 --- a/25_day/beepup.c +++ /dev/null @@ -1,22 +0,0 @@ -void api_end(void); -int api_getkey(int mode); -int api_alloctimer(void); -void api_inittimer(int timer, int data); -void api_settimer(int timer, int time); -void api_beep(int tone); - -void HariMain(void) -{ - int i, timer; - timer = api_alloctimer(); - api_inittimer(timer, 128); - for (i = 20000; i <= 20000000; i += i / 100) { - api_beep(i); - api_settimer(timer, 1); /* 0.01秒*/ - if (api_getkey(1) != 128) { - break; - } - } - api_beep(0); - api_end(); -} diff --git a/25_day/bug2.c b/25_day/bug2.c deleted file mode 100644 index c6f65e7..0000000 --- a/25_day/bug2.c +++ /dev/null @@ -1,3 +0,0 @@ -void HariMain(void){ - for (;;) { } -} \ No newline at end of file diff --git a/25_day/bug3.c b/25_day/bug3.c deleted file mode 100644 index 5982e10..0000000 --- a/25_day/bug3.c +++ /dev/null @@ -1,9 +0,0 @@ -void api_putchar(int c); -void api_end(void); - -void HariMain(void) -{ - for (;;) { - api_putchar('a'); - } -} From 9d45d34cce7f162a3687ab71fcf00ec2d0f5e261 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Mon, 16 May 2016 10:44:14 +0800 Subject: [PATCH 24/83] Add 26 day code --- 26_day/!cons_9x.bat | 1 + 26_day/!cons_nt.bat | 1 + 26_day/Makefile | 232 +++ 26_day/a.c | 8 + 26_day/a_nask.nas | 230 +++ 26_day/asmhead.nas | 202 ++ 26_day/beepdown.c | 24 + 26_day/bootpack.c | 305 +++ 26_day/bootpack.h | 274 +++ 26_day/color.c | 27 + 26_day/color2.c | 42 + 26_day/console.c | 516 +++++ 26_day/dsctbl.c | 59 + 26_day/fifo.c | 63 + 26_day/file.c | 74 + 26_day/graphic.c | 167 ++ 26_day/hankaku.txt | 4609 +++++++++++++++++++++++++++++++++++++++++++ 26_day/hello.nas | 16 + 26_day/hello2.nas | 9 + 26_day/hello3.c | 12 + 26_day/hello4.c | 8 + 26_day/hello5.nas | 20 + 26_day/int.c | 26 + 26_day/ipl10.nas | 109 + 26_day/keyboard.c | 44 + 26_day/lines.c | 29 + 26_day/make.bat | 1 + 26_day/memory.c | 162 ++ 26_day/mouse.c | 76 + 26_day/mtask.c | 202 ++ 26_day/naskfunc.nas | 291 +++ 26_day/noodle.c | 42 + 26_day/sheet.c | 217 ++ 26_day/star1.c | 18 + 26_day/stars.c | 24 + 26_day/stars2.c | 26 + 26_day/timer.c | 169 ++ 26_day/walk.c | 35 + 26_day/window.c | 118 ++ 26_day/winhelo.c | 11 + 26_day/winhelo2.c | 15 + 26_day/winhelo3.c | 19 + 42 files changed, 8533 insertions(+) create mode 100644 26_day/!cons_9x.bat create mode 100644 26_day/!cons_nt.bat create mode 100644 26_day/Makefile create mode 100644 26_day/a.c create mode 100644 26_day/a_nask.nas create mode 100644 26_day/asmhead.nas create mode 100644 26_day/beepdown.c create mode 100644 26_day/bootpack.c create mode 100644 26_day/bootpack.h create mode 100644 26_day/color.c create mode 100644 26_day/color2.c create mode 100644 26_day/console.c create mode 100644 26_day/dsctbl.c create mode 100644 26_day/fifo.c create mode 100644 26_day/file.c create mode 100644 26_day/graphic.c create mode 100644 26_day/hankaku.txt create mode 100644 26_day/hello.nas create mode 100644 26_day/hello2.nas create mode 100644 26_day/hello3.c create mode 100644 26_day/hello4.c create mode 100644 26_day/hello5.nas create mode 100644 26_day/int.c create mode 100644 26_day/ipl10.nas create mode 100644 26_day/keyboard.c create mode 100644 26_day/lines.c create mode 100644 26_day/make.bat create mode 100644 26_day/memory.c create mode 100644 26_day/mouse.c create mode 100644 26_day/mtask.c create mode 100644 26_day/naskfunc.nas create mode 100644 26_day/noodle.c create mode 100644 26_day/sheet.c create mode 100644 26_day/star1.c create mode 100644 26_day/stars.c create mode 100644 26_day/stars2.c create mode 100644 26_day/timer.c create mode 100644 26_day/walk.c create mode 100644 26_day/window.c create mode 100644 26_day/winhelo.c create mode 100644 26_day/winhelo2.c create mode 100644 26_day/winhelo3.c diff --git a/26_day/!cons_9x.bat b/26_day/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/26_day/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/26_day/!cons_nt.bat b/26_day/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/26_day/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/26_day/Makefile b/26_day/Makefile new file mode 100644 index 0000000..8714cad --- /dev/null +++ b/26_day/Makefile @@ -0,0 +1,232 @@ +OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \ + int.obj fifo.obj keyboard.obj mouse.obj memory.obj sheet.obj timer.obj \ + mtask.obj window.obj console.obj file.obj + +TOOLPATH = ../z_tools/ +INCPATH = ../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = $(TOOLPATH)haribote/haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +COPY = copy +DEL = del + +# 默认动作 + +default : + $(MAKE) img + +# 镜像文件生成 + +ipl10.bin : ipl10.nas Makefile + $(NASK) ipl10.nas ipl10.bin ipl10.lst + +asmhead.bin : asmhead.nas Makefile + $(NASK) asmhead.nas asmhead.bin asmhead.lst + +hankaku.bin : hankaku.txt Makefile + $(MAKEFONT) hankaku.txt hankaku.bin + +hankaku.obj : hankaku.bin Makefile + $(BIN2OBJ) hankaku.bin hankaku.obj _hankaku + +bootpack.bim : $(OBJS_BOOTPACK) Makefile + $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \ + $(OBJS_BOOTPACK) +# 3MB+64KB=3136KB + +bootpack.hrb : bootpack.bim Makefile + $(BIM2HRB) bootpack.bim bootpack.hrb 0 + +haribote.sys : asmhead.bin bootpack.hrb Makefile + copy /B asmhead.bin+bootpack.hrb haribote.sys + +hello.hrb : hello.nas Makefile + $(NASK) hello.nas hello.hrb hello.lst + +hello2.hrb : hello2.nas Makefile + $(NASK) hello2.nas hello2.hrb hello2.lst + +a.bim : a.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:a.bim map:a.map a.obj a_nask.obj + +a.hrb : a.bim Makefile + $(BIM2HRB) a.bim a.hrb 0 + +hello3.bim : hello3.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello3.bim map:hello3.map hello3.obj a_nask.obj + +hello3.hrb : hello3.bim Makefile + $(BIM2HRB) hello3.bim hello3.hrb 0 + +hello4.bim : hello4.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello4.bim stack:1k map:hello4.map \ + hello4.obj a_nask.obj + +hello4.hrb : hello4.bim Makefile + $(BIM2HRB) hello4.bim hello4.hrb 0 + +hello5.bim : hello5.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello5.bim stack:1k map:hello5.map hello5.obj + +hello5.hrb : hello5.bim Makefile + $(BIM2HRB) hello5.bim hello5.hrb 0 + +winhelo.bim : winhelo.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:winhelo.bim stack:1k map:winhelo.map \ + winhelo.obj a_nask.obj + +winhelo.hrb : winhelo.bim Makefile + $(BIM2HRB) winhelo.bim winhelo.hrb 0 + +winhelo2.bim : winhelo2.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:winhelo2.bim stack:1k map:winhelo2.map \ + winhelo2.obj a_nask.obj + +winhelo2.hrb : winhelo2.bim Makefile + $(BIM2HRB) winhelo2.bim winhelo2.hrb 0 + +winhelo3.bim : winhelo3.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:winhelo3.bim stack:1k map:winhelo3.map \ + winhelo3.obj a_nask.obj + +winhelo3.hrb : winhelo3.bim Makefile + $(BIM2HRB) winhelo3.bim winhelo3.hrb 40k + +star1.bim : star1.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:star1.bim stack:1k map:star1.map \ + star1.obj a_nask.obj + +star1.hrb : star1.bim Makefile + $(BIM2HRB) star1.bim star1.hrb 47k + +stars.bim : stars.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:stars.bim stack:1k map:stars.map \ + stars.obj a_nask.obj + +stars.hrb : stars.bim Makefile + $(BIM2HRB) stars.bim stars.hrb 47k + +stars2.bim : stars2.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:stars2.bim stack:1k map:stars2.map \ + stars2.obj a_nask.obj + +stars2.hrb : stars2.bim Makefile + $(BIM2HRB) stars2.bim stars2.hrb 47k + +lines.bim : lines.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:lines.bim stack:1k map:lines.map \ + lines.obj a_nask.obj + +lines.hrb : lines.bim Makefile + $(BIM2HRB) lines.bim lines.hrb 48k + +walk.bim : walk.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:walk.bim stack:1k map:walk.map \ + walk.obj a_nask.obj + +walk.hrb : walk.bim Makefile + $(BIM2HRB) walk.bim walk.hrb 48k + +noodle.bim : noodle.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:noodle.bim stack:1k map:noodle.map \ + noodle.obj a_nask.obj + +noodle.hrb : noodle.bim Makefile + $(BIM2HRB) noodle.bim noodle.hrb 40k + +beepdown.bim : beepdown.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:beepdown.bim stack:1k map:beepdown.map \ + beepdown.obj a_nask.obj + +beepdown.hrb : beepdown.bim Makefile + $(BIM2HRB) beepdown.bim beepdown.hrb 40k + +color.bim : color.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:color.bim stack:1k map:color.map \ + color.obj a_nask.obj + +color.hrb : color.bim Makefile + $(BIM2HRB) color.bim color.hrb 56k + +color2.bim : color2.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:color2.bim stack:1k map:color2.map \ + color2.obj a_nask.obj + +color2.hrb : color2.bim Makefile + $(BIM2HRB) color2.bim color2.hrb 56k + +haribote.img : ipl10.bin haribote.sys Makefile \ + hello.hrb hello2.hrb a.hrb hello3.hrb hello4.hrb hello5.hrb \ + winhelo.hrb winhelo2.hrb winhelo3.hrb star1.hrb stars.hrb stars2.hrb \ + lines.hrb walk.hrb noodle.hrb beepdown.hrb color.hrb color2.hrb + $(EDIMG) imgin:../z_tools/fdimg0at.tek \ + wbinimg src:ipl10.bin len:512 from:0 to:0 \ + copy from:haribote.sys to:@: \ + copy from:ipl10.nas to:@: \ + copy from:make.bat to:@: \ + copy from:hello.hrb to:@: \ + copy from:hello2.hrb to:@: \ + copy from:a.hrb to:@: \ + copy from:hello3.hrb to:@: \ + copy from:hello4.hrb to:@: \ + copy from:hello5.hrb to:@: \ + copy from:winhelo.hrb to:@: \ + copy from:winhelo2.hrb to:@: \ + copy from:winhelo3.hrb to:@: \ + copy from:star1.hrb to:@: \ + copy from:stars.hrb to:@: \ + copy from:stars2.hrb to:@: \ + copy from:lines.hrb to:@: \ + copy from:walk.hrb to:@: \ + copy from:noodle.hrb to:@: \ + copy from:beepdown.hrb to:@: \ + copy from:color.hrb to:@: \ + copy from:color2.hrb to:@: \ + imgout:haribote.img + +# 其他指令 + +%.gas : %.c bootpack.h Makefile + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +# 运行程序 + +img : + $(MAKE) haribote.img + +run : + $(MAKE) img + $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../z_tools/qemu + +install : + $(MAKE) img + $(IMGTOL) w a: haribote.img + +clean : + -$(DEL) *.bin + -$(DEL) *.lst + -$(DEL) *.obj + -$(DEL) bootpack.map + -$(DEL) bootpack.bim + -$(DEL) bootpack.hrb + -$(DEL) haribote.sys + +src_only : + $(MAKE) clean + -$(DEL) haribote.img diff --git a/26_day/a.c b/26_day/a.c new file mode 100644 index 0000000..a6668af --- /dev/null +++ b/26_day/a.c @@ -0,0 +1,8 @@ +void api_putchar(int c); +void api_end(void); + +void HariMain(void) +{ + api_putchar('A'); + api_end(); +} diff --git a/26_day/a_nask.nas b/26_day/a_nask.nas new file mode 100644 index 0000000..9e63654 --- /dev/null +++ b/26_day/a_nask.nas @@ -0,0 +1,230 @@ +[FORMAT "WCOFF"] ; 生成对象文件的模式 +[INSTRSET "i486p"] ; 表示使用486兼容指令集 +[BITS 32] ; 生成32位模式机器语言 +[FILE "a_nask.nas"] ; 源文件名信息 + + GLOBAL _api_putchar + GLOBAL _api_putstr0 + GLOBAL _api_end + GLOBAL _api_openwin + GLOBAL _api_putstrwin + GLOBAL _api_boxfilwin + GLOBAL _api_initmalloc + GLOBAL _api_malloc + GLOBAL _api_free + GLOBAL _api_point + GLOBAL _api_refreshwin + GLOBAL _api_linewin + GLOBAL _api_closewin + GLOBAL _api_getkey + GLOBAL _api_alloctimer + GLOBAL _api_inittimer + GLOBAL _api_settimer + GLOBAL _api_freetimer + GLOBAL _api_beep + +[SECTION .text] + +_api_putchar: ; void api_putchar(int c); + MOV EDX,1 + MOV AL,[ESP+4] ; c + INT 0x40 + RET + +_api_putstr0: ; void api_putstr0(char *s); + PUSH EBX + MOV EDX,2 + MOV EBX,[ESP+8] ; s + INT 0x40 + POP EBX + RET + +_api_end: ; void api_end(void); + MOV EDX,4 + INT 0x40 + +_api_openwin: ; int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,5 + MOV EBX,[ESP+16] ; buf + MOV ESI,[ESP+20] ; xsiz + MOV EDI,[ESP+24] ; ysiz + MOV EAX,[ESP+28] ; col_inv + MOV ECX,[ESP+32] ; title + INT 0x40 + POP EBX + POP ESI + POP EDI + RET + +_api_putstrwin: ; void api_putstrwin(int win, int x, int y, int col, int len, char *str); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,6 + MOV EBX,[ESP+20] ; win + MOV ESI,[ESP+24] ; x + MOV EDI,[ESP+28] ; y + MOV EAX,[ESP+32] ; col + MOV ECX,[ESP+36] ; len + MOV EBP,[ESP+40] ; str + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET + +_api_boxfilwin: ; void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,7 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET + +_api_initmalloc: ; void api_initmalloc(void); + PUSH EBX + MOV EDX,8 + MOV EBX,[CS:0x0020] ; malloc内存空间的地址 + MOV EAX,EBX + ADD EAX,32*1024 ; 加上32KB + MOV ECX,[CS:0x0000] ; 数据段的大小 + SUB ECX,EAX + INT 0x40 + POP EBX + RET + +_api_malloc: ; char *api_malloc(int size); + PUSH EBX + MOV EDX,9 + MOV EBX,[CS:0x0020] + MOV ECX,[ESP+8] ; size + INT 0x40 + POP EBX + RET + +_api_free: ; void api_free(char *addr, int size); + PUSH EBX + MOV EDX,10 + MOV EBX,[CS:0x0020] + MOV EAX,[ESP+ 8] ; addr + MOV ECX,[ESP+12] ; size + INT 0x40 + POP EBX + RET + +_api_point: ; void api_point(int win, int x, int y, int col); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,11 + MOV EBX,[ESP+16] ; win + MOV ESI,[ESP+20] ; x + MOV EDI,[ESP+24] ; y + MOV EAX,[ESP+28] ; col + INT 0x40 + POP EBX + POP ESI + POP EDI + RET + +_api_refreshwin: ; void api_refreshwin(int win, int x0, int y0, int x1, int y1); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,12 + MOV EBX,[ESP+16] ; win + MOV EAX,[ESP+20] ; x0 + MOV ECX,[ESP+24] ; y0 + MOV ESI,[ESP+28] ; x1 + MOV EDI,[ESP+32] ; y1 + INT 0x40 + POP EBX + POP ESI + POP EDI + RET + +_api_linewin: ; void api_linewin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,13 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET + +_api_closewin: ; void api_closewin(int win); + PUSH EBX + MOV EDX,14 + MOV EBX,[ESP+8] ; win + INT 0x40 + POP EBX + RET + +_api_getkey: ; int api_getkey(int mode); + MOV EDX,15 + MOV EAX,[ESP+4] ; mode + INT 0x40 + RET + +_api_alloctimer: ; int api_alloctimer(void); + MOV EDX,16 + INT 0x40 + RET + +_api_inittimer: ; void api_inittimer(int timer, int data); + PUSH EBX + MOV EDX,17 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; data + INT 0x40 + POP EBX + RET + +_api_settimer: ; void api_settimer(int timer, int time); + PUSH EBX + MOV EDX,18 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; time + INT 0x40 + POP EBX + RET + +_api_freetimer: ; void api_freetimer(int timer); + PUSH EBX + MOV EDX,19 + MOV EBX,[ESP+ 8] ; timer + INT 0x40 + POP EBX + RET + +_api_beep: ; void api_beep(int tone); + MOV EDX,20 + MOV EAX,[ESP+4] ; tone + INT 0x40 + RET diff --git a/26_day/asmhead.nas b/26_day/asmhead.nas new file mode 100644 index 0000000..ad35d76 --- /dev/null +++ b/26_day/asmhead.nas @@ -0,0 +1,202 @@ +; haribote-os boot asm +; TAB=4 + +[INSTRSET "i486p"] + +VBEMODE EQU 0x105 ; 1024 x 768 x 8bit 彩色 +; 显示模式 +; 0x100 : 640 x 400 x 8bit 彩色 +; 0x101 : 640 x 480 x 8bit 彩色 +; 0x103 : 800 x 600 x 8bit 彩色 +; 0x105 : 1024 x 768 x 8bit 彩色 +; 0x107 : 1280 x 1024 x 8bit 彩色 + +BOTPAK EQU 0x00280000 ; 加载bootpack +DSKCAC EQU 0x00100000 ; 磁盘缓存的位置 +DSKCAC0 EQU 0x00008000 ; 磁盘缓存的位置(实模式) + +; BOOT_INFO 相关 +CYLS EQU 0x0ff0 ; 引导扇区设置 +LEDS EQU 0x0ff1 +VMODE EQU 0x0ff2 ; 关于颜色的信息 +SCRNX EQU 0x0ff4 ; 分辨率X +SCRNY EQU 0x0ff6 ; 分辨率Y +VRAM EQU 0x0ff8 ; 图像缓冲区的起始地址 + + ORG 0xc200 ; 这个的程序要被装载的内存地址 + +; 确认VBE是否存在 + + MOV AX,0x9000 + MOV ES,AX + MOV DI,0 + MOV AX,0x4f00 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 检查VBE的版本 + + MOV AX,[ES:DI+4] + CMP AX,0x0200 + JB scrn320 ; if (AX < 0x0200) goto scrn320 + +; 取得画面模式信息 + + MOV CX,VBEMODE + MOV AX,0x4f01 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 画面模式信息的确认 + CMP BYTE [ES:DI+0x19],8 ;颜色数必须为8 + JNE scrn320 + CMP BYTE [ES:DI+0x1b],4 ;颜色的指定方法必须为4(4是调色板模式) + JNE scrn320 + MOV AX,[ES:DI+0x00] ;模式属性bit7不是1就不能加上0x4000 + AND AX,0x0080 + JZ scrn320 ; 模式属性的bit7是0,所以放弃 + +; 画面设置 + + MOV BX,VBEMODE+0x4000 + MOV AX,0x4f02 + INT 0x10 + MOV BYTE [VMODE],8 ; 屏幕的模式(参考C语言的引用) + MOV AX,[ES:DI+0x12] + MOV [SCRNX],AX + MOV AX,[ES:DI+0x14] + MOV [SCRNY],AX + MOV EAX,[ES:DI+0x28] ;VRAM的地址 + MOV [VRAM],EAX + JMP keystatus + +scrn320: + MOV AL,0x13 ; VGA图、320x200x8bit彩色 + MOV AH,0x00 + INT 0x10 + MOV BYTE [VMODE],8 ; 记下画面模式(参考C语言) + MOV WORD [SCRNX],320 + MOV WORD [SCRNY],200 + MOV DWORD [VRAM],0x000a0000 + +; 通过 BIOS 获取指示灯状态 + +keystatus: + MOV AH,0x02 + INT 0x16 ; keyboard BIOS + MOV [LEDS],AL + +; PIC关闭一切中断 +; 根据AT兼容机的规格,如果要初始化PIC, +; 必须在CLI之前进行,否则有时会挂起。 +; 随后进行PIC的初始化。 + + MOV AL,0xff + OUT 0x21,AL + NOP ; 如果连续执行OUT指令,有些机种会无法正常运行 + OUT 0xa1,AL + + CLI ; 禁止CPU级别的中断 + +; 为了让CPU能够访问1MB以上的内存空间,设定A20GATE + + CALL waitkbdout + MOV AL,0xd1 + OUT 0x64,AL + CALL waitkbdout + MOV AL,0xdf ; enable A20 + OUT 0x60,AL + CALL waitkbdout + +; 切换到保护模式 + +[INSTRSET "i486p"] ; 说明使用486指令 + + LGDT [GDTR0] ; 设置临时GDT + MOV EAX,CR0 + AND EAX,0x7fffffff ; 设bit31为0(禁用分页) + OR EAX,0x00000001 ; bit0到1转换(保护模式过渡) + MOV CR0,EAX + JMP pipelineflush +pipelineflush: + MOV AX,1*8 ; 可读写的段 32bit + MOV DS,AX + MOV ES,AX + MOV FS,AX + MOV GS,AX + MOV SS,AX + +; bootpack传递 + + MOV ESI,bootpack ; 转送源 + MOV EDI,BOTPAK ; 转送目标 + MOV ECX,512*1024/4 + CALL memcpy + +; 磁盘数据最终转送到它本来的位置去 +; 首先从启动扇区开始 + + MOV ESI,0x7c00 ; 转送源 + MOV EDI,DSKCAC ; 转送目标 + MOV ECX,512/4 + CALL memcpy + +; 剩余的全部 + + MOV ESI,DSKCAC0+512 ; 转送源 + MOV EDI,DSKCAC+512 ; 转送源目标 + MOV ECX,0 + MOV CL,BYTE [CYLS] + IMUL ECX,512*18*2/4 ; 从柱面数变换为字节数/4 + SUB ECX,512/4 ; 减去 IPL 偏移量 + CALL memcpy + +; 必须由asmhead来完成的工作,至此全部完毕 +; 以后就交由bootpack来完成 + +; bootpack启动 + + MOV EBX,BOTPAK + MOV ECX,[EBX+16] + ADD ECX,3 ; ECX += 3; + SHR ECX,2 ; ECX /= 4; + JZ skip ; 没有要转送的东西时 + MOV ESI,[EBX+20] ; 转送源 + ADD ESI,EBX + MOV EDI,[EBX+12] ; 转送目标 + CALL memcpy +skip: + MOV ESP,[EBX+12] ; 堆栈的初始化 + JMP DWORD 2*8:0x0000001b + +waitkbdout: + IN AL,0x64 + AND AL,0x02 + JNZ waitkbdout ; AND的结果如果不是0,就跳到waitkbdout + RET + +memcpy: + MOV EAX,[ESI] + ADD ESI,4 + MOV [EDI],EAX + ADD EDI,4 + SUB ECX,1 + JNZ memcpy ; 减法运算的结果如果不是0,就跳转到memcpy + RET +; memcpy地址前缀大小 + + ALIGNB 16 +GDT0: + RESB 8 ; 初始值 + DW 0xffff,0x0000,0x9200,0x00cf ; 可以读写的段(segment)32bit + DW 0xffff,0x0000,0x9a28,0x0047 ; 可执行的文件的32bit寄存器(bootpack用) + + DW 0 +GDTR0: + DW 8*3-1 + DD GDT0 + + ALIGNB 16 +bootpack: diff --git a/26_day/beepdown.c b/26_day/beepdown.c new file mode 100644 index 0000000..db1aa59 --- /dev/null +++ b/26_day/beepdown.c @@ -0,0 +1,24 @@ +void api_end(void); +int api_getkey(int mode); +int api_alloctimer(void); +void api_inittimer(int timer, int data); +void api_settimer(int timer, int time); +void api_beep(int tone); + +void HariMain(void) +{ + int i, timer; + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (i = 20000000; i >= 20000; i -= i / 100) { + /* 20KHz~20Hz,即人类可以听到的声音范围*/ + /* i以1%的速度递减*/ + api_beep(i); + api_settimer(timer, 1); /* 0.01秒*/ + if (api_getkey(1) != 128) { + break; + } + } + api_beep(0); + api_end(); +} diff --git a/26_day/bootpack.c b/26_day/bootpack.c new file mode 100644 index 0000000..d2aa307 --- /dev/null +++ b/26_day/bootpack.c @@ -0,0 +1,305 @@ +/* bootpack */ + +#include "bootpack.h" +#include + +#define KEYCMD_LED 0xed + +void keywin_off(struct SHEET *key_win); +void keywin_on(struct SHEET *key_win); + +void HariMain(void) +{ + struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; + struct SHTCTL *shtctl; + char s[40]; + struct FIFO32 fifo, keycmd; + int fifobuf[128], keycmd_buf[32], *cons_fifo[2]; + int mx, my, i; + unsigned int memtotal; + struct MOUSE_DEC mdec; + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + unsigned char *buf_back, buf_mouse[256], *buf_cons[2]; + struct SHEET *sht_back, *sht_mouse, *sht_cons[2]; + struct TASK *task_a, *task_cons[2], *task; + static char keytable0[0x80] = { + 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0x08, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0x0a, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0 + }; + static char keytable1[0x80] = { + 0, 0, '!', 0x22, '#', '$', '%', '&', 0x27, '(', ')', '~', '=', '~', 0x08, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0x0a, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', '+', '*', 0, 0, '}', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, '|', 0, 0 + }; + int key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; + int j, x, y, mmx = -1, mmy = -1; + struct SHEET *sht = 0, *key_win; + + init_gdtidt(); + init_pic(); + io_sti(); /* IDT/PIC的初始化已经完成,于是开放CPU的中断 */ + fifo32_init(&fifo, 128, fifobuf, 0); + init_pit(); + init_keyboard(&fifo, 256); + enable_mouse(&fifo, 512, &mdec); + io_out8(PIC0_IMR, 0xf8); /* 设定PIT和PIC1以及键盘为许可(11111000) */ + io_out8(PIC1_IMR, 0xef); /* 开放鼠标中断(11101111) */ + fifo32_init(&keycmd, 32, keycmd_buf, 0); + + memtotal = memtest(0x00400000, 0xbfffffff); + memman_init(memman); + memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */ + memman_free(memman, 0x00400000, memtotal - 0x00400000); + + init_palette(); + shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny); + task_a = task_init(memman); + fifo.task = task_a; + task_run(task_a, 1, 2); + *((int *) 0x0fe4) = (int) shtctl; + + /* sht_back */ + sht_back = sheet_alloc(shtctl); + buf_back = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny); + sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 无透明色 */ + init_screen8(buf_back, binfo->scrnx, binfo->scrny); + + /* sht_cons */ + for (i = 0; i < 2; i++) { + sht_cons[i] = sheet_alloc(shtctl); + buf_cons[i] = (unsigned char *) memman_alloc_4k(memman, 256 * 165); + sheet_setbuf(sht_cons[i], buf_cons[i], 256, 165, -1); /*没有透明色*/ + make_window8(buf_cons[i], 256, 165, "console", 0); + make_textbox8(sht_cons[i], 8, 28, 240, 128, COL8_000000); + task_cons[i] = task_alloc(); + task_cons[i]->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 12; + task_cons[i]->tss.eip = (int) &console_task; + task_cons[i]->tss.es = 1 * 8; + task_cons[i]->tss.cs = 2 * 8; + task_cons[i]->tss.ss = 1 * 8; + task_cons[i]->tss.ds = 1 * 8; + task_cons[i]->tss.fs = 1 * 8; + task_cons[i]->tss.gs = 1 * 8; + *((int *) (task_cons[i]->tss.esp + 4)) = (int) sht_cons[i]; + *((int *) (task_cons[i]->tss.esp + 8)) = memtotal; + task_run(task_cons[i], 2, 2); /* level=2, priority=2 */ + sht_cons[i]->task = task_cons[i]; + sht_cons[i]->flags |= 0x20; /*有光标*/ + cons_fifo[i] = (int *) memman_alloc_4k(memman, 128 * 4); + fifo32_init(&task_cons[i]->fifo, 128, cons_fifo[i], task_cons[i]); + } + + /* sht_mouse */ + sht_mouse = sheet_alloc(shtctl); + sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99); + init_mouse_cursor8(buf_mouse, 99); + mx = (binfo->scrnx - 16) / 2; /* 计算坐标使其位于画面中央 */ + my = (binfo->scrny - 28 - 16) / 2; + + sheet_slide(sht_back, 0, 0); + sheet_slide(sht_cons[1], 56, 6); + sheet_slide(sht_cons[0], 8, 2); + sheet_slide(sht_mouse, mx, my); + sheet_updown(sht_back, 0); + sheet_updown(sht_cons[1], 1); + sheet_updown(sht_cons[0], 2); + sheet_updown(sht_mouse, 3); + key_win = sht_cons[0]; + keywin_on(key_win); + + /*为了避免和键盘当前状态冲突,在一开始先进行设置*/ + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + + for (;;) { + if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0) { + /* �L�[�{�[�h�R���g���[���ɑ���f�[�^������΁A���� */ + keycmd_wait = fifo32_get(&keycmd); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + io_cli(); + if (fifo32_status(&fifo) == 0) { + task_sleep(task_a); + io_sti(); + } else { + i = fifo32_get(&fifo); + io_sti(); + if (key_win->flags == 0) { /*输入窗口被关闭*/ + key_win = shtctl->sheets[shtctl->top - 1]; + keywin_on(key_win); + } + if (256 <= i && i <= 511) { /* 键盘数据*/ + if (i < 0x80 + 256) { /*将按键编码转换为字符编码*/ + if (key_shift == 0) { + s[0] = keytable0[i - 256]; + } else { + s[0] = keytable1[i - 256]; + } + } else { + s[0] = 0; + } + if ('A' <= s[0] && s[0] <= 'Z') { /*当输入字符为英文字母时*/ + if (((key_leds & 4) == 0 && key_shift == 0) || + ((key_leds & 4) != 0 && key_shift != 0)) { + s[0] += 0x20; /*将大写字母转换为小写字母*/ + } + } + if (s[0] != 0) { /*一般字符、退格键、回车键*/ + fifo32_put(&key_win->task->fifo, s[0] + 256); + } + if (i == 256 + 0x0f) { /* Tab键 */ + keywin_off(key_win); + j = key_win->height - 1; + if (j == 0) { + j = shtctl->top - 1; + } + key_win = shtctl->sheets[j]; + keywin_on(key_win); + } + if (i == 256 + 0x2a) { /*左Shift ON */ + key_shift |= 1; + } + if (i == 256 + 0x36) { /*右Shift ON */ + key_shift |= 2; + } + if (i == 256 + 0xaa) { /*左Shift OFF */ + key_shift &= ~1; + } + if (i == 256 + 0xb6) { /*右Shift OFF */ + key_shift &= ~2; + } + if (i == 256 + 0x3a) { /* CapsLock */ + key_leds ^= 4; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x45) { /* NumLock */ + key_leds ^= 2; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x46) { /* ScrollLock */ + key_leds ^= 1; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x3b && key_shift != 0) { + task = key_win->task; + if (task != 0 && task->tss.ss0 != 0) { /* Shift+F1 */ + cons_putstr0(task->cons, "\nBreak(key) :\n"); + io_cli(); /*强制结束处理时禁止任务切换*/ + task->tss.eax = (int) &(task->tss.esp0); + task->tss.eip = (int) asm_end_app; + io_sti(); + } + } + if (i == 256 + 0x57) { /* F11 */ + sheet_updown(shtctl->sheets[1], shtctl->top - 1); + } + if (i == 256 + 0xfa) { /*键盘成功接收到数据*/ + keycmd_wait = -1; + } + if (i == 256 + 0xfe) { /*键盘没有成功接收到数据*/ + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + } else if (512 <= i && i <= 767) { /* 鼠标数据*/ + if (mouse_decode(&mdec, i - 512) != 0) { + /* 已经收集了3字节的数据,移动光标 */ + mx += mdec.x; + my += mdec.y; + if (mx < 0) { + mx = 0; + } + if (my < 0) { + my = 0; + } + if (mx > binfo->scrnx - 1) { + mx = binfo->scrnx - 1; + } + if (my > binfo->scrny - 1) { + my = binfo->scrny - 1; + } + sheet_slide(sht_mouse, mx, my);/* 包含sheet_refresh含sheet_refresh */ + if ((mdec.btn & 0x01) != 0) { /* 按下左键 */ + if (mmx < 0) { + /*如果处于通常模式*/ + /*按照从上到下的顺序寻找鼠标所指向的图层*/ + for (j = shtctl->top - 1; j > 0; j--) { + sht = shtctl->sheets[j]; + x = mx - sht->vx0; + y = my - sht->vy0; + if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) { + if (sht->buf[y * sht->bxsize + x] != sht->col_inv) { + sheet_updown(sht, shtctl->top - 1); + if (sht != key_win) { + keywin_off(key_win); + key_win = sht; + keywin_on(key_win); + } + if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) { + mmx = mx; /*进入窗口移动模式*/ + mmy = my; + } + if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <= y && y < 19) { + /*点击“×”按钮*/ + if ((sht->flags & 0x10) != 0) { /*该窗口是否为应用程序窗口?*/ + task = sht->task; + cons_putstr0(task->cons, "\nBreak(mouse) :\n"); + io_cli(); /*强制结束处理时禁止任务切换*/ + task->tss.eax = (int) &(task->tss.esp0); + task->tss.eip = (int) asm_end_app; + io_sti(); + } + } + break; + } + } + } + } else { + /*如果处于窗口移动模式*/ + x = mx - mmx; /*计算鼠标的移动距离*/ + y = my - mmy; + sheet_slide(sht, sht->vx0 + x, sht->vy0 + y); + mmx = mx; /*更新为移动后的坐标*/ + mmy = my; + } + } else { + /*没有按下左键*/ + mmx = -1; /*返回通常模式*/ + } + } + } + } + } +} + +void keywin_off(struct SHEET *key_win) +{ + change_wtitle8(key_win, 0); + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 3); /*命令行窗口光标OFF */ + } + return; +} + +void keywin_on(struct SHEET *key_win) +{ + change_wtitle8(key_win, 1); + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 2); /*命令行窗口光标ON */ + } + return; +} diff --git a/26_day/bootpack.h b/26_day/bootpack.h new file mode 100644 index 0000000..9975f09 --- /dev/null +++ b/26_day/bootpack.h @@ -0,0 +1,274 @@ +/* asmhead.nas */ +struct BOOTINFO { /* 0x0ff0-0x0fff */ + char cyls; /* 启动区读磁盘读到此为止 */ + char leds; /* 启动时键盘的LED的状态 */ + char vmode; /* 显卡模式为多少位彩色 */ + char reserve; + short scrnx, scrny; /* 画面分辨率 */ + char *vram; +}; +#define ADR_BOOTINFO 0x00000ff0 +#define ADR_DISKIMG 0x00100000 + +/* naskfunc.nas */ +void io_hlt(void); +void io_cli(void); +void io_sti(void); +void io_stihlt(void); +int io_in8(int port); +void io_out8(int port, int data); +int io_load_eflags(void); +void io_store_eflags(int eflags); +void load_gdtr(int limit, int addr); +void load_idtr(int limit, int addr); +int load_cr0(void); +void store_cr0(int cr0); +void load_tr(int tr); +void asm_inthandler0c(void); +void asm_inthandler0d(void); +void asm_inthandler20(void); +void asm_inthandler21(void); +void asm_inthandler2c(void); +unsigned int memtest_sub(unsigned int start, unsigned int end); +void farjmp(int eip, int cs); +void farcall(int eip, int cs); +void asm_hrb_api(void); +void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); +void asm_end_app(void); + +/* fifo.c */ +struct FIFO32 { + int *buf; + int p, q, size, free, flags; + struct TASK *task; +}; +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task); +int fifo32_put(struct FIFO32 *fifo, int data); +int fifo32_get(struct FIFO32 *fifo); +int fifo32_status(struct FIFO32 *fifo); + +/* graphic.c */ +void init_palette(void); +void set_palette(int start, int end, unsigned char *rgb); +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); +void init_screen8(char *vram, int x, int y); +void putfont8(char *vram, int xsize, int x, int y, char c, char *font); +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s); +void init_mouse_cursor8(char *mouse, char bc); +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize); +#define COL8_000000 0 +#define COL8_FF0000 1 +#define COL8_00FF00 2 +#define COL8_FFFF00 3 +#define COL8_0000FF 4 +#define COL8_FF00FF 5 +#define COL8_00FFFF 6 +#define COL8_FFFFFF 7 +#define COL8_C6C6C6 8 +#define COL8_840000 9 +#define COL8_008400 10 +#define COL8_848400 11 +#define COL8_000084 12 +#define COL8_840084 13 +#define COL8_008484 14 +#define COL8_848484 15 + +/* dsctbl.c */ +struct SEGMENT_DESCRIPTOR { + short limit_low, base_low; + char base_mid, access_right; + char limit_high, base_high; +}; +struct GATE_DESCRIPTOR { + short offset_low, selector; + char dw_count, access_right; + short offset_high; +}; +void init_gdtidt(void); +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar); +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar); +#define ADR_IDT 0x0026f800 +#define LIMIT_IDT 0x000007ff +#define ADR_GDT 0x00270000 +#define LIMIT_GDT 0x0000ffff +#define ADR_BOTPAK 0x00280000 +#define LIMIT_BOTPAK 0x0007ffff +#define AR_DATA32_RW 0x4092 +#define AR_CODE32_ER 0x409a +#define AR_TSS32 0x0089 +#define AR_INTGATE32 0x008e + +/* int.c */ +void init_pic(void); +#define PIC0_ICW1 0x0020 +#define PIC0_OCW2 0x0020 +#define PIC0_IMR 0x0021 +#define PIC0_ICW2 0x0021 +#define PIC0_ICW3 0x0021 +#define PIC0_ICW4 0x0021 +#define PIC1_ICW1 0x00a0 +#define PIC1_OCW2 0x00a0 +#define PIC1_IMR 0x00a1 +#define PIC1_ICW2 0x00a1 +#define PIC1_ICW3 0x00a1 +#define PIC1_ICW4 0x00a1 + +/* keyboard.c */ +void inthandler21(int *esp); +void wait_KBC_sendready(void); +void init_keyboard(struct FIFO32 *fifo, int data0); +#define PORT_KEYDAT 0x0060 +#define PORT_KEYCMD 0x0064 + +/* mouse.c */ +struct MOUSE_DEC { + unsigned char buf[3], phase; + int x, y, btn; +}; +void inthandler2c(int *esp); +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec); +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat); + +/* memory.c */ +#define MEMMAN_FREES 4090 /* ����Ŗ�32KB */ +#define MEMMAN_ADDR 0x003c0000 +struct FREEINFO { /* ������� */ + unsigned int addr, size; +}; +struct MEMMAN { /* �������Ǘ� */ + int frees, maxfrees, lostsize, losts; + struct FREEINFO free[MEMMAN_FREES]; +}; +unsigned int memtest(unsigned int start, unsigned int end); +void memman_init(struct MEMMAN *man); +unsigned int memman_total(struct MEMMAN *man); +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size); +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size); +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size); +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size); + +/* sheet.c */ +#define MAX_SHEETS 256 +struct SHEET { + unsigned char *buf; + int bxsize, bysize, vx0, vy0, col_inv, height, flags; + struct SHTCTL *ctl; + struct TASK *task; +}; +struct SHTCTL { + unsigned char *vram, *map; + int xsize, ysize, top; + struct SHEET *sheets[MAX_SHEETS]; + struct SHEET sheets0[MAX_SHEETS]; +}; +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize); +struct SHEET *sheet_alloc(struct SHTCTL *ctl); +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv); +void sheet_updown(struct SHEET *sht, int height); +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1); +void sheet_slide(struct SHEET *sht, int vx0, int vy0); +void sheet_free(struct SHEET *sht); + +/* timer.c */ +#define MAX_TIMER 500 +struct TIMER { + struct TIMER *next; + unsigned int timeout; + char flags, flags2; + struct FIFO32 *fifo; + int data; +}; +struct TIMERCTL { + unsigned int count, next; + struct TIMER *t0; + struct TIMER timers0[MAX_TIMER]; +}; +extern struct TIMERCTL timerctl; +void init_pit(void); +struct TIMER *timer_alloc(void); +void timer_free(struct TIMER *timer); +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data); +void timer_settime(struct TIMER *timer, unsigned int timeout); +void inthandler20(int *esp); +int timer_cancel(struct TIMER *timer); +void timer_cancelall(struct FIFO32 *fifo); + +/* mtask.c */ +#define MAX_TASKS 1000 /*最大任务数量*/ +#define TASK_GDT0 3 /*定义从GDT的几号开始分配给TSS */ +#define MAX_TASKS_LV 100 +#define MAX_TASKLEVELS 10 +struct TSS32 { + int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3; + int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi; + int es, cs, ss, ds, fs, gs; + int ldtr, iomap; +}; +struct TASK { + int sel, flags; /* sel用来存放GDT的编号*/ + int level, priority; /* 优先级 */ + struct FIFO32 fifo; + struct TSS32 tss; + struct CONSOLE *cons; + int ds_base; +}; +struct TASKLEVEL { + int running; /*正在运行的任务数量*/ + int now; /*这个变量用来记录当前正在运行的是哪个任务*/ + struct TASK *tasks[MAX_TASKS_LV]; +}; +struct TASKCTL { + int now_lv; /*现在活动中的LEVEL */ + char lv_change; /*在下次任务切换时是否需要改变LEVEL */ + struct TASKLEVEL level[MAX_TASKLEVELS]; + struct TASK tasks0[MAX_TASKS]; +}; +extern struct TIMER *task_timer; +struct TASK *task_now(void); +struct TASK *task_init(struct MEMMAN *memman); +struct TASK *task_alloc(void); +void task_run(struct TASK *task, int level, int priority); +void task_switch(void); +void task_sleep(struct TASK *task); + +/* window.c */ +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act); +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l); +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c); +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act); +void change_wtitle8(struct SHEET *sht, char act); + +/* console.c */ +struct CONSOLE { + struct SHEET *sht; + int cur_x, cur_y, cur_c; + struct TIMER *timer; +}; +void console_task(struct SHEET *sheet, int memtotal); +void cons_putchar(struct CONSOLE *cons, int chr, char move); +void cons_newline(struct CONSOLE *cons); +void cons_putstr0(struct CONSOLE *cons, char *s); +void cons_putstr1(struct CONSOLE *cons, char *s, int l); +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal); +void cmd_mem(struct CONSOLE *cons, int memtotal); +void cmd_cls(struct CONSOLE *cons); +void cmd_dir(struct CONSOLE *cons); +void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline); +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline); +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax); +int *inthandler0d(int *esp); +int *inthandler0c(int *esp); +void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col); + +/* file.c */ +struct FILEINFO { + unsigned char name[8], ext[3], type; + char reserve[10]; + unsigned short time, date, clustno; + unsigned int size; +}; +void file_readfat(int *fat, unsigned char *img); +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img); +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max); + diff --git a/26_day/color.c b/26_day/color.c new file mode 100644 index 0000000..c004c14 --- /dev/null +++ b/26_day/color.c @@ -0,0 +1,27 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +int api_getkey(int mode); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win, x, y, r, g, b; + api_initmalloc(); + buf = api_malloc(144 * 164); + win = api_openwin(buf, 144, 164, -1, "color"); + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) { + r = x * 2; + g = y * 2; + b = 0; + buf[(x + 8) + (y + 28) * 144] = 16 + (r / 43) + (g / 43) * 6 + (b / 43) * 36; + } + } + api_refreshwin(win, 8, 28, 136, 156); + api_getkey(1); /*等待按下任意键*/ + api_end(); +} diff --git a/26_day/color2.c b/26_day/color2.c new file mode 100644 index 0000000..c063768 --- /dev/null +++ b/26_day/color2.c @@ -0,0 +1,42 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +int api_getkey(int mode); +void api_end(void); + +unsigned char rgb2pal(int r, int g, int b, int x, int y); + +void HariMain(void) +{ + char *buf; + int win, x, y; + api_initmalloc(); + buf = api_malloc(144 * 164); + win = api_openwin(buf, 144, 164, -1, "color2"); + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) { + buf[(x + 8) + (y + 28) * 144] = rgb2pal(x * 2, y * 2, 0, x, y); + } + } + api_refreshwin(win, 8, 28, 136, 156); + api_getkey(1); /*等待按下任意键*/ + api_end(); +} + +unsigned char rgb2pal(int r, int g, int b, int x, int y) +{ + static int table[4] = { 3, 1, 0, 2 }; + int i; + x &= 1; /*判断是偶数还是奇数*/ + y &= 1; + i = table[x + y * 2]; /*用来生成中间色的常量*/ + r = (r * 21) / 256; /* r为0~20*/ + g = (g * 21) / 256; + b = (b * 21) / 256; + r = (r + i) / 4; /* r为0~5*/ + g = (g + i) / 4; + b = (b + i) / 4; + return 16 + r + g * 6 + b * 36; +} diff --git a/26_day/console.c b/26_day/console.c new file mode 100644 index 0000000..7df9bea --- /dev/null +++ b/26_day/console.c @@ -0,0 +1,516 @@ +/* 命令行窗口相关 */ + +#include "bootpack.h" +#include +#include + +void console_task(struct SHEET *sheet, int memtotal) +{ + struct TASK *task = task_now(); + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + int i, *fat = (int *) memman_alloc_4k(memman, 4 * 2880); + struct CONSOLE cons; + char cmdline[30]; + cons.sht = sheet; + cons.cur_x = 8; + cons.cur_y = 28; + cons.cur_c = -1; + task->cons = &cons; + + cons.timer = timer_alloc(); + timer_init(cons.timer, &task->fifo, 1); + timer_settime(cons.timer, 50); + file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); + + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + task_sleep(task); + io_sti(); + } else { + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1) { /*光标用定时器*/ + if (i != 0) { + timer_init(cons.timer, &task->fifo, 0); /*下次置0 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_FFFFFF; + } + } else { + timer_init(cons.timer, &task->fifo, 1); /*下次置1 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_000000; + } + } + timer_settime(cons.timer, 50); + } + if (i == 2) { /*光标ON */ + cons.cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + boxfill8(sheet->buf, sheet->bxsize, COL8_000000, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + cons.cur_c = -1; + } + if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/ + if (i == 8 + 256) { + /*退格键*/ + if (cons.cur_x > 16) { + /*用空格擦除光标后将光标前移一位*/ + cons_putchar(&cons, ' ', 0); + cons.cur_x -= 8; + } + } else if (i == 10 + 256) { + /*回车键*/ + /*将光标用空格擦除后换行 */ + cons_putchar(&cons, ' ', 0); + cmdline[cons.cur_x / 8 - 2] = 0; + cons_newline(&cons); + cons_runcmd(cmdline, &cons, fat, memtotal); /*运行命令*/ + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + } else { + /*一般字符*/ + if (cons.cur_x < 240) { + /*显示一个字符之后将光标后移一位*/ + cmdline[cons.cur_x / 8 - 2] = i - 256; + cons_putchar(&cons, i - 256, 1); + } + } + } + /*重新显示光标*/ + if (cons.cur_c >= 0) { + boxfill8(sheet->buf, sheet->bxsize, cons.cur_c, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + } + sheet_refresh(sheet, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16); + } + } +} + +void cons_putchar(struct CONSOLE *cons, int chr, char move) +{ + char s[2]; + s[0] = chr; + s[1] = 0; + if (s[0] == 0x09) { /*制表符*/ + for (;;) { + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1); + cons->cur_x += 8; + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + if (((cons->cur_x - 8) & 0x1f) == 0) { + break; /*被32整除则break*/ + } + } + } else if (s[0] == 0x0a) { /*换行*/ + cons_newline(cons); + } else if (s[0] == 0x0d) { /*回车*/ + /*先不做任何操作*/ + } else { /*一般字符*/ + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1); + if (move != 0) { + /* move为0时光标不后移*/ + cons->cur_x += 8; + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + } + } + return; +} + +void cons_newline(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + if (cons->cur_y < 28 + 112) { + cons->cur_y += 16; /*到下一行*/ + } else { + /*滚动*/ + for (y = 28; y < 28 + 112; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize]; + } + } + for (y = 28 + 112; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + } + cons->cur_x = 8; + return; +} + +void cons_putstr0(struct CONSOLE *cons, char *s) +{ + for (; *s != 0; s++) { + cons_putchar(cons, *s, 1); + } + return; +} + +void cons_putstr1(struct CONSOLE *cons, char *s, int l) +{ + int i; + for (i = 0; i < l; i++) { + cons_putchar(cons, s[i], 1); + } + return; +} + +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) +{ + if (strcmp(cmdline, "mem") == 0) { + cmd_mem(cons, memtotal); + } else if (strcmp(cmdline, "cls") == 0) { + cmd_cls(cons); + } else if (strcmp(cmdline, "dir") == 0 || strcmp(cmdline, "ls") == 0) { + cmd_dir(cons); + } else if (strncmp(cmdline, "type ", 5) == 0) { + cmd_type(cons, fat, cmdline); + } else if (cmdline[0] != 0) { + if (cmd_app(cons, fat, cmdline) == 0) { + /*不是命令,不是应用程序,也不是空行*/ + cons_putstr0(cons, "Bad command.\n\n"); + } + } + return; +} + +void cmd_mem(struct CONSOLE *cons, int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + char s[60]; + sprintf(s, "total %dMB\nfree %dKB\n\n", memtotal / (1024 * 1024), memman_total(memman) / 1024); + cons_putstr0(cons, s); + return; +} + +void cmd_cls(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + for (y = 28; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + cons->cur_y = 28; + return; +} + +void cmd_dir(struct CONSOLE *cons) +{ + struct FILEINFO *finfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600); + int i, j; + char s[30]; + for (i = 0; i < 224; i++) { + if (finfo[i].name[0] == 0x00) { + break; + } + if (finfo[i].name[0] != 0xe5) { + if ((finfo[i].type & 0x18) == 0) { + sprintf(s, "filename.ext %7d\n", finfo[i].size); + for (j = 0; j < 8; j++) { + s[j] = finfo[i].name[j]; + } + s[ 9] = finfo[i].ext[0]; + s[10] = finfo[i].ext[1]; + s[11] = finfo[i].ext[2]; + cons_putstr0(cons, s); + } + } + } + cons_newline(cons); + return; +} + +void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct FILEINFO *finfo = file_search(cmdline + 5, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + char *p; + if (finfo != 0) { + /*找到文件的情况*/ + p = (char *) memman_alloc_4k(memman, finfo->size); + file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); + cons_putstr1(cons, p, finfo->size); + memman_free_4k(memman, (int) p, finfo->size); + } else { + /*没有找到文件的情况*/ + cons_putstr0(cons, "File not found.\n"); + } + cons_newline(cons); + return; +} + +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct FILEINFO *finfo; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + char name[18], *p, *q; + struct TASK *task = task_now(); + int i, segsiz, datsiz, esp, dathrb; + struct SHTCTL *shtctl; + struct SHEET *sht; + + /*根据命令行生成文件名*/ + for (i = 0; i < 13; i++) { + if (cmdline[i] <= ' ') { + break; + } + name[i] = cmdline[i]; + } + name[i] = 0; /*暂且将文件名的后面置为0*/ + + /*寻找文件 */ + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + if (finfo == 0 && name[i - 1] != '.') { + /*由于找不到文件,故在文件名后面加上“.hrb”后重新寻找*/ + name[i ] = '.'; + name[i + 1] = 'H'; + name[i + 2] = 'R'; + name[i + 3] = 'B'; + name[i + 4] = 0; + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + } + + if (finfo != 0) { + /*找到文件的情况*/ + p = (char *) memman_alloc_4k(memman, finfo->size); + file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); + if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) { + segsiz = *((int *) (p + 0x0000)); + esp = *((int *) (p + 0x000c)); + datsiz = *((int *) (p + 0x0010)); + dathrb = *((int *) (p + 0x0014)); + q = (char *) memman_alloc_4k(memman, segsiz); + task->ds_base = (int) q; + set_segmdesc(gdt + task->sel / 8 + 1000, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); + set_segmdesc(gdt + task->sel / 8 + 2000, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); + for (i = 0; i < datsiz; i++) { + q[esp + i] = p[dathrb + i]; + } + start_app(0x1b, task->sel + 1000 * 8, esp, task->sel + 2000 * 8, &(task->tss.esp0)); + shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + for (i = 0; i < MAX_SHEETS; i++) { + sht = &(shtctl->sheets0[i]); + if ((sht->flags & 0x11) == 0x11 && sht->task == task) { + /*找到被应用程序遗留的窗口*/ + sheet_free(sht); /*关闭*/ + } + } + timer_cancelall(&task->fifo); + memman_free_4k(memman, (int) q, segsiz); + } else { + cons_putstr0(cons, ".hrb file format error.\n"); + } + memman_free_4k(memman, (int) p, finfo->size); + cons_newline(cons); + return 1; + } + /*没有找到文件的情况*/ + return 0; +} + +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) +{ + struct TASK *task = task_now(); + int ds_base = task->ds_base; + struct CONSOLE *cons = task->cons; + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct SHEET *sht; + int *reg = &eax + 1; /* eax后面的地址*/ + /*强行改写通过PUSHAD保存的值*/ + /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */ + /* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ + int i; + + if (edx == 1) { + cons_putchar(cons, eax & 0xff, 1); + } else if (edx == 2) { + cons_putstr0(cons, (char *) ebx + ds_base); + } else if (edx == 3) { + cons_putstr1(cons, (char *) ebx + ds_base, ecx); + } else if (edx == 4) { + return &(task->tss.esp0); + } else if (edx == 5) { + sht = sheet_alloc(shtctl); + sht->task = task; + sht->flags |= 0x10; + sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax); + make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0); + sheet_slide(sht, (shtctl->xsize - esi) / 2, (shtctl->ysize - edi) / 2); + sheet_updown(sht, shtctl->top); /*将窗口图层高度指定为当前鼠标所在图层的高度,鼠标移到上层*/ + reg[7] = (int) sht; + } else if (edx == 6) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + putfonts8_asc(sht->buf, sht->bxsize, esi, edi, eax, (char *) ebp + ds_base); + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + ecx * 8, edi + 16); + } + } else if (edx == 7) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + boxfill8(sht->buf, sht->bxsize, ebp, eax, ecx, esi, edi); + if ((ebx & 1) == 0) { + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 8) { + memman_init((struct MEMMAN *) (ebx + ds_base)); + ecx &= 0xfffffff0; /*以16字节为单位*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 9) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + reg[7] = memman_alloc((struct MEMMAN *) (ebx + ds_base), ecx); + } else if (edx == 10) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 11) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + sht->buf[sht->bxsize * edi + esi] = eax; + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + 1, edi + 1); + } + } else if (edx == 12) { + sht = (struct SHEET *) ebx; + sheet_refresh(sht, eax, ecx, esi, edi); + } else if (edx == 13) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + hrb_api_linewin(sht, eax, ecx, esi, edi, ebp); + if ((ebx & 1) == 0) { + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 14) { + sheet_free((struct SHEET *) ebx); + } else if (edx == 15) { + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + if (eax != 0) { + task_sleep(task); /* FIFO为空,休眠并等待*/ + } else { + io_sti(); + reg[7] = -1; + return 0; + } + } + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1) { /*光标用定时器*/ + /*应用程序运行时不需要显示光标,因此总是将下次显示用的值置为1*/ + timer_init(cons->timer, &task->fifo, 1); /*下次置为1*/ + timer_settime(cons->timer, 50); + } + if (i == 2) { /*光标ON */ + cons->cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + cons->cur_c = -1; + } + if (i >= 256) { /*键盘数据(通过任务A)等*/ + reg[7] = i - 256; + return 0; + } + } + } else if (edx == 16) { + reg[7] = (int) timer_alloc(); + ((struct TIMER *) reg[7])->flags2 = 1; /*允许自动取消*/ + } else if (edx == 17) { + timer_init((struct TIMER *) ebx, &task->fifo, eax + 256); + } else if (edx == 18) { + timer_settime((struct TIMER *) ebx, eax); + } else if (edx == 19) { + timer_free((struct TIMER *) ebx); + } else if (edx == 20) { + if (eax == 0) { + i = io_in8(0x61); + io_out8(0x61, i & 0x0d); + } else { + i = 1193180000 / eax; + io_out8(0x43, 0xb6); + io_out8(0x42, i & 0xff); + io_out8(0x42, i >> 8); + i = io_in8(0x61); + io_out8(0x61, (i | 0x03) & 0x0f); + } + } + return 0; +} + +int *inthandler0c(int *esp) +{ + struct TASK *task = task_now(); + struct CONSOLE *cons = task->cons; + char s[30]; + cons_putstr0(cons, "\nINT 0C :\n Stack Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +int *inthandler0d(int *esp) +{ + struct TASK *task = task_now(); + struct CONSOLE *cons = task->cons; + char s[30]; + cons_putstr0(cons, "\nINT 0D :\n General Protected Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col) +{ + int i, x, y, len, dx, dy; + + dx = x1 - x0; + dy = y1 - y0; + x = x0 << 10; + y = y0 << 10; + if (dx < 0) { + dx = - dx; + } + if (dy < 0) { + dy = - dy; + } + if (dx >= dy) { + len = dx + 1; + if (x0 > x1) { + dx = -1024; + } else { + dx = 1024; + } + if (y0 <= y1) { + dy = ((y1 - y0 + 1) << 10) / len; + } else { + dy = ((y1 - y0 - 1) << 10) / len; + } + } else { + len = dy + 1; + if (y0 > y1) { + dy = -1024; + } else { + dy = 1024; + } + if (x0 <= x1) { + dx = ((x1 - x0 + 1) << 10) / len; + } else { + dx = ((x1 - x0 - 1) << 10) / len; + } + } + + for (i = 0; i < len; i++) { + sht->buf[(y >> 10) * sht->bxsize + (x >> 10)] = col; + x += dx; + y += dy; + } + + return; +} diff --git a/26_day/dsctbl.c b/26_day/dsctbl.c new file mode 100644 index 0000000..9ff2c67 --- /dev/null +++ b/26_day/dsctbl.c @@ -0,0 +1,59 @@ +/* GDT、IDT、descriptor table 关系处理 */ + +#include "bootpack.h" + +void init_gdtidt(void) +{ + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *) ADR_IDT; + int i; + + /* GDT初始化 */ + for (i = 0; i <= LIMIT_GDT / 8; i++) { + set_segmdesc(gdt + i, 0, 0, 0); + } + set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW); + set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER); + load_gdtr(LIMIT_GDT, ADR_GDT); + + /* IDT初始化 */ + for (i = 0; i <= LIMIT_IDT / 8; i++) { + set_gatedesc(idt + i, 0, 0, 0); + } + load_idtr(LIMIT_IDT, ADR_IDT); + + /* IDT设置*/ + set_gatedesc(idt + 0x0c, (int) asm_inthandler0c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x0d, (int) asm_inthandler0d, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x40, (int) asm_hrb_api, 2 * 8, AR_INTGATE32 + 0x60); + + return; +} + +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar) +{ + if (limit > 0xfffff) { + ar |= 0x8000; /* G_bit = 1 */ + limit /= 0x1000; + } + sd->limit_low = limit & 0xffff; + sd->base_low = base & 0xffff; + sd->base_mid = (base >> 16) & 0xff; + sd->access_right = ar & 0xff; + sd->limit_high = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0); + sd->base_high = (base >> 24) & 0xff; + return; +} + +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar) +{ + gd->offset_low = offset & 0xffff; + gd->selector = selector; + gd->dw_count = (ar >> 8) & 0xff; + gd->access_right = ar & 0xff; + gd->offset_high = (offset >> 16) & 0xffff; + return; +} diff --git a/26_day/fifo.c b/26_day/fifo.c new file mode 100644 index 0000000..8f28f4b --- /dev/null +++ b/26_day/fifo.c @@ -0,0 +1,63 @@ +/* FIFO */ + +#include "bootpack.h" + +#define FLAGS_OVERRUN 0x0001 + +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task) +/* FIFO缓冲区的初始化*/ +{ + fifo->size = size; + fifo->buf = buf; + fifo->free = size; /*空*/ + fifo->flags = 0; + fifo->p = 0; /*写入位置*/ + fifo->q = 0; /*读取位置*/ + fifo->task = task; /*有数据写入时需要唤醒的任务*/ + return; +} + +int fifo32_put(struct FIFO32 *fifo, int data) +/*向FIFO写入数据并累积起来*/ +{ + if (fifo->free == 0) { + /*没有空余空间,溢出*/ + fifo->flags |= FLAGS_OVERRUN; + return -1; + } + fifo->buf[fifo->p] = data; + fifo->p++; + if (fifo->p == fifo->size) { + fifo->p = 0; + } + fifo->free--; + if (fifo->task != 0) { + if (fifo->task->flags != 2) { /*如果任务处于休眠状态*/ + task_run(fifo->task, -1, 0); /*将任务唤醒*/ + } + } + return 0; +} + +int fifo32_get(struct FIFO32 *fifo) +/*从FIFO取得一个数据*/ +{ + int data; + if (fifo->free == fifo->size) { + /*当缓冲区为空的情况下返回-1*/ + return -1; + } + data = fifo->buf[fifo->q]; + fifo->q++; + if (fifo->q == fifo->size) { + fifo->q = 0; + } + fifo->free++; + return data; +} + +int fifo32_status(struct FIFO32 *fifo) +/*报告已经存储了多少数据*/ +{ + return fifo->size - fifo->free; +} diff --git a/26_day/file.c b/26_day/file.c new file mode 100644 index 0000000..bf9d063 --- /dev/null +++ b/26_day/file.c @@ -0,0 +1,74 @@ +/* 文件相关函数 */ + +#include "bootpack.h" + +void file_readfat(int *fat, unsigned char *img) +/*将磁盘映像中的FAT解压缩 */ +{ + int i, j = 0; + for (i = 0; i < 2880; i += 2) { + fat[i + 0] = (img[j + 0] | img[j + 1] << 8) & 0xfff; + fat[i + 1] = (img[j + 1] >> 4 | img[j + 2] << 4) & 0xfff; + j += 3; + } + return; +} + +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img) +{ + int i; + for (;;) { + if (size <= 512) { + for (i = 0; i < size; i++) { + buf[i] = img[clustno * 512 + i]; + } + break; + } + for (i = 0; i < 512; i++) { + buf[i] = img[clustno * 512 + i]; + } + size -= 512; + buf += 512; + clustno = fat[clustno]; + } + return; +} + +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max) +{ + int i, j; + char s[12]; + for (j = 0; j < 11; j++) { + s[j] = ' '; + } + j = 0; + for (i = 0; name[i] != 0; i++) { + if (j >= 11) { return 0; /*没有找到*/ } + if (name[i] == '.' && j <= 8) { + j = 8; + } else { + s[j] = name[i]; + if ('a' <= s[j] && s[j] <= 'z') { + /*将小写字母转换为大写字母*/ + s[j] -= 0x20; + } + j++; + } + } + for (i = 0; i < max; ) { + if (finfo->name[0] == 0x00) { + break; + } + if ((finfo[i].type & 0x18) == 0) { + for (j = 0; j < 11; j++) { + if (finfo[i].name[j] != s[j]) { + goto next; + } + } + return finfo + i; /*找到文件*/ + } +next: + i++; + } + return 0; /*没有找到*/ +} diff --git a/26_day/graphic.c b/26_day/graphic.c new file mode 100644 index 0000000..4bd6979 --- /dev/null +++ b/26_day/graphic.c @@ -0,0 +1,167 @@ +/* 关于绘图部分的处理 */ + +#include "bootpack.h" + +void init_palette(void) +{ + static unsigned char table_rgb[16 * 3] = { + 0x00, 0x00, 0x00, /* 0:黑 */ + 0xff, 0x00, 0x00, /* 1:梁红 */ + 0x00, 0xff, 0x00, /* 2:亮绿 */ + 0xff, 0xff, 0x00, /* 3:亮黄 */ + 0x00, 0x00, 0xff, /* 4:亮蓝 */ + 0xff, 0x00, 0xff, /* 5:亮紫 */ + 0x00, 0xff, 0xff, /* 6:浅亮蓝 */ + 0xff, 0xff, 0xff, /* 7:白 */ + 0xc6, 0xc6, 0xc6, /* 8:亮灰 */ + 0x84, 0x00, 0x00, /* 9:暗红 */ + 0x00, 0x84, 0x00, /* 10:暗绿 */ + 0x84, 0x84, 0x00, /* 11:暗黄 */ + 0x00, 0x00, 0x84, /* 12:暗青 */ + 0x84, 0x00, 0x84, /* 13:暗紫 */ + 0x00, 0x84, 0x84, /* 14:浅暗蓝 */ + 0x84, 0x84, 0x84 /* 15:暗灰 */ + }; + unsigned char table2[216 * 3]; + int r, g, b; + set_palette(0, 15, table_rgb); + for (b = 0; b < 6; b++) { + for (g = 0; g < 6; g++) { + for (r = 0; r < 6; r++) { + table2[(r + g * 6 + b * 36) * 3 + 0] = r * 51; + table2[(r + g * 6 + b * 36) * 3 + 1] = g * 51; + table2[(r + g * 6 + b * 36) * 3 + 2] = b * 51; + } + } + } + set_palette(16, 231, table2); + return; +} + +void set_palette(int start, int end, unsigned char *rgb) +{ + int i, eflags; + eflags = io_load_eflags(); /* 记录中断许可标志的值 */ + io_cli(); /* 将中断许可标志置为0,禁止中断 */ + io_out8(0x03c8, start); + for (i = start; i <= end; i++) { + io_out8(0x03c9, rgb[0] / 4); + io_out8(0x03c9, rgb[1] / 4); + io_out8(0x03c9, rgb[2] / 4); + rgb += 3; + } + io_store_eflags(eflags); /* 复原中断许可标志 */ + return; +} + +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) +{ + int x, y; + for (y = y0; y <= y1; y++) { + for (x = x0; x <= x1; x++) + vram[y * xsize + x] = c; + } + return; +} + +void init_screen8(char *vram, int x, int y) +{ + boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28); + boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1); + + boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24); + boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4); + boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4); + boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5); + boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3); + boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3); + + boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24); + boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4); + boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3); + boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3); + return; +} + +void putfont8(char *vram, int xsize, int x, int y, char c, char *font) +{ + int i; + char *p, d /* data */; + for (i = 0; i < 16; i++) { + p = vram + (y + i) * xsize + x; + d = font[i]; + if ((d & 0x80) != 0) { p[0] = c; } + if ((d & 0x40) != 0) { p[1] = c; } + if ((d & 0x20) != 0) { p[2] = c; } + if ((d & 0x10) != 0) { p[3] = c; } + if ((d & 0x08) != 0) { p[4] = c; } + if ((d & 0x04) != 0) { p[5] = c; } + if ((d & 0x02) != 0) { p[6] = c; } + if ((d & 0x01) != 0) { p[7] = c; } + } + return; +} + +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s) +{ + extern char hankaku[4096]; + /* C语言中,字符串都是以0x00结尾 */ + for (; *s != 0x00; s++) { + putfont8(vram, xsize, x, y, c, hankaku + *s * 16); + x += 8; + } + return; +} + +void init_mouse_cursor8(char *mouse, char bc) +/* 鼠标的数据准备(16x16) */ +{ + static char cursor[16][16] = { + "**************..", + "*OOOOOOOOOOO*...", + "*OOOOOOOOOO*....", + "*OOOOOOOOO*.....", + "*OOOOOOOO*......", + "*OOOOOOO*.......", + "*OOOOOOO*.......", + "*OOOOOOOO*......", + "*OOOO**OOO*.....", + "*OOO*..*OOO*....", + "*OO*....*OOO*...", + "*O*......*OOO*..", + "**........*OOO*.", + "*..........*OOO*", + "............*OO*", + ".............***" + }; + int x, y; + + for (y = 0; y < 16; y++) { + for (x = 0; x < 16; x++) { + if (cursor[y][x] == '*') { + mouse[y * 16 + x] = COL8_000000; + } + if (cursor[y][x] == 'O') { + mouse[y * 16 + x] = COL8_FFFFFF; + } + if (cursor[y][x] == '.') { + mouse[y * 16 + x] = bc; + } + } + } + return; +} + +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize) +{ + int x, y; + for (y = 0; y < pysize; y++) { + for (x = 0; x < pxsize; x++) { + vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x]; + } + } + return; +} diff --git a/26_day/hankaku.txt b/26_day/hankaku.txt new file mode 100644 index 0000000..62d56f9 --- /dev/null +++ b/26_day/hankaku.txt @@ -0,0 +1,4609 @@ +OSASK̔ptHg𗬗p + +char 0x00 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x01 +........ +........ +..***... +.*...*.. +*.....*. +*.*.*.*. +*.*.*.*. +*.....*. +*.....*. +*.*.*.*. +*..*..*. +.*...*.. +..***... +........ +........ +........ + +char 0x02 +........ +........ +..***... +.*****.. +*******. +**.*.**. +**.*.**. +*******. +*******. +**.*.**. +***.***. +.*****.. +..***... +........ +........ +........ + +char 0x03 +........ +........ +........ +........ +.**.**.. +*******. +*******. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x04 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x05 +........ +........ +........ +........ +...*.... +..***... +.*.*.*.. +*******. +.*.*.*.. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x06 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +**.*.**. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x07 +........ +........ +........ +........ +........ +........ +...**... +..****.. +..****.. +...**... +........ +........ +........ +........ +........ +........ + +char 0x08 +******** +******** +******** +******** +******** +******** +***..*** +**....** +**....** +***..*** +******** +******** +******** +******** +******** +******** + +char 0x09 +........ +........ +........ +........ +........ +..****.. +.**..**. +.*....*. +.*....*. +.**..**. +..****.. +........ +........ +........ +........ +........ + +char 0x0a +******** +******** +******** +******** +******** +**....** +*..**..* +*.****.* +*.****.* +*..**..* +**....** +******** +******** +******** +******** +******** + +char 0x0b +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x0c +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ + +char 0x0d +........ +........ +....**.. +....***. +....*.** +....*.** +....*.*. +....*... +....*... +...**... +.****... +*****... +.***.... +........ +........ +........ + +char 0x0e +........ +........ +...***** +...***** +...*...* +...*...* +...*...* +...*...* +...*...* +...*...* +.***.*** +******** +.**..**. +........ +........ +........ + +char 0x0f +........ +........ +........ +........ +...*.... +.*.*.*.. +..***... +..*.*... +..***... +.*.*.*.. +...*.... +........ +........ +........ +........ +........ + +char 0x10 +........ +*....... +**...... +***..... +****.... +*****... +******.. +*******. +******.. +*****... +****.... +***..... +**...... +*....... +........ +........ + +char 0x11 +........ +......*. +.....**. +....***. +...****. +..*****. +.******. +*******. +.******. +..*****. +...****. +....***. +.....**. +......*. +........ +........ + +char 0x12 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ +........ + +char 0x13 +........ +........ +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +........ +........ +.*...*.. +.*...*.. +........ +........ + +char 0x14 +........ +..*****. +.*..*.*. +*...*.*. +*...*.*. +*...*.*. +*...*.*. +.*..*.*. +..***.*. +....*.*. +....*.*. +....*.*. +....*.*. +....*.*. +........ +........ + +char 0x15 +.*****.. +*.....*. +.*...... +..*..... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +....*... +.....*.. +*.....*. +.*****.. +........ + +char 0x16 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*******. +*******. +........ +........ + +char 0x17 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +.*****.. +........ +........ + +char 0x18 +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x19 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ + +char 0x1a +........ +........ +........ +........ +...*.... +....*... +.....*.. +*******. +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ + +char 0x1b +........ +........ +........ +........ +...*.... +..*..... +.*...... +*******. +.*...... +..*..... +...*.... +........ +........ +........ +........ +........ + +char 0x1c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*....... +*....... +*******. +........ +........ + +char 0x1d +........ +........ +........ +........ +........ +..*.*... +.*...*.. +*******. +.*...*.. +..*.*... +........ +........ +........ +........ +........ +........ + +char 0x1e +........ +........ +........ +........ +...*.... +...*.... +..***... +..***... +.*****.. +.*****.. +*******. +*******. +........ +........ +........ +........ + +char 0x1f +........ +........ +........ +........ +*******. +*******. +.*****.. +.*****.. +..***... +..***... +...*.... +...*.... +........ +........ +........ +........ + +char 0x20 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x21 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ +...*.... +...*.... +........ +........ + +char 0x22 +..*.*... +..*.*... +..*.*... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x23 +........ +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +........ +........ + +char 0x24 +...*.... +..***.*. +.*.*.**. +*..*..*. +*..*..*. +*..*.... +.*.*.... +..***... +...*.*.. +...*..*. +*..*..*. +*..*..*. +**.*.*.. +*.***... +...*.... +...*.... + +char 0x25 +.**...*. +*..*..*. +*..*.*.. +*..*.*.. +.**.*... +....*... +...*.... +...*.... +..*..... +..*.**.. +.*.*..*. +.*.*..*. +*..*..*. +*...**.. +........ +........ + +char 0x26 +........ +.***.... +*...*... +*...*... +*...*... +*..*.... +.**..... +.*...*** +*.*...*. +*..*..*. +*...*.*. +*....*.. +.*...**. +..***..* +........ +........ + +char 0x27 +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x28 +......*. +.....*.. +....*... +....*... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....*... +....*... +.....*.. +......*. +........ + +char 0x29 +*....... +.*...... +..*..... +..*..... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..*..... +..*..... +.*...... +*....... +........ + +char 0x2a +........ +........ +........ +........ +........ +...*.... +*..*..*. +.*.*.*.. +..***... +.*.*.*.. +*..*..*. +...*.... +........ +........ +........ +........ + +char 0x2b +........ +........ +........ +........ +........ +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ +........ +........ + +char 0x2c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x2d +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ +........ +........ +........ +........ +........ +........ + +char 0x2e +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x2f +......*. +......*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*...... +.*...... +*....... +*....... + +char 0x30 +........ +...**... +..*..*.. +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +...**... +........ +........ + +char 0x31 +........ +....*... +...**... +..*.*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +..*****. +........ +........ + +char 0x32 +........ +...**... +..*..*.. +.*....*. +.*....*. +......*. +.....*.. +....*... +...*.... +..*..... +..*..... +.*...... +.*...... +.******. +........ +........ + +char 0x33 +........ +...**... +..*..*.. +.*....*. +......*. +......*. +.....*.. +...**... +.....*.. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x34 +........ +....**.. +....**.. +....**.. +...*.*.. +...*.*.. +...*.*.. +..*..*.. +..*..*.. +.*...*.. +.******. +.....*.. +.....*.. +...****. +........ +........ + +char 0x35 +........ +.*****.. +.*...... +.*...... +.*...... +.*.**... +.**..*.. +......*. +......*. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x36 +........ +...**... +..*..*.. +.*....*. +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x37 +........ +.******. +.*....*. +.*....*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x38 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x39 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..**. +...**.*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x3a +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x3b +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x3c +........ +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +........ + +char 0x3d +........ +........ +........ +........ +........ +........ +*******. +........ +........ +*******. +........ +........ +........ +........ +........ +........ + +char 0x3e +........ +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +........ + +char 0x3f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.....*.. +....*... +...*.... +...*.... +........ +........ +...**... +...**... +........ +........ + +char 0x40 +........ +..***... +.*...*.. +*.....*. +*..**.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*..***.. +*....... +.*...**. +..***... +........ +........ + +char 0x41 +........ +...**... +...**... +...**... +...**... +..*..*.. +..*..*.. +..*..*.. +..*..*.. +.******. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x42 +........ +****.... +.*..*... +.*...*.. +.*...*.. +.*...*.. +.*..*... +.****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +*****... +........ +........ + +char 0x43 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*....... +*....... +*....... +*.....*. +.*....*. +.*...*.. +..***... +........ +........ + +char 0x44 +........ +*****... +.*...*.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...*.. +.*...*.. +*****... +........ +........ + +char 0x45 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x46 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...*.. +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x47 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*..****. +*.....*. +*.....*. +*.....*. +.*....*. +.*...**. +..***... +........ +........ + +char 0x48 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.******. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x49 +........ +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x4a +........ +...***** +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +*....*.. +.*..*... +..**.... +........ + +char 0x4b +........ +***..*** +.*....*. +.*...*.. +.*..*... +.*.*.... +.*.*.... +.**..... +.*.*.... +.*.*.... +.*..*... +.*...*.. +.*....*. +***..*** +........ +........ + +char 0x4c +........ +****.... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x4d +........ +**....** +.*....*. +.**..**. +.**..**. +.**..**. +.*.**.*. +.*.**.*. +.*.**.*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x4e +........ +**...*** +.*....*. +.**...*. +.**...*. +.*.*..*. +.*.*..*. +.*.*..*. +.*..*.*. +.*..*.*. +.*..*.*. +.*...**. +.*...**. +***...*. +........ +........ + +char 0x4f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x50 +........ +*****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +.****... +.*...... +.*...... +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x51 +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*..*..*. +*...*.*. +.*...*.. +..***.*. +........ +........ + +char 0x52 +........ +******.. +.*....*. +.*....*. +.*....*. +.*....*. +.*****.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x53 +........ +..***.*. +.*...**. +*.....*. +*.....*. +*....... +.*...... +..***... +.....*.. +......*. +*.....*. +*.....*. +**...*.. +*.***... +........ +........ + +char 0x54 +........ +*******. +*..*..*. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x55 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..****.. +........ +........ + +char 0x56 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...**... +...**... +........ +........ + +char 0x57 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x58 +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +..*..*.. +..*..*.. +..*..*.. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x59 +........ +***.***. +.*...*.. +.*...*.. +.*...*.. +..*.*... +..*.*... +..*.*... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x5a +........ +*******. +*....*.. +*....*.. +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*....*. +*.....*. +*******. +........ +........ + +char 0x5b +........ +..*****. +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*****. +........ + +char 0x5c +*....... +*....... +.*...... +.*...... +..*..... +..*..... +..*..... +...*.... +...*.... +....*... +....*... +.....*.. +.....*.. +.....*.. +......*. +......*. + +char 0x5d +........ +.*****.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.*****.. +........ + +char 0x5e +........ +...*.... +..*.*... +.*...*.. +*.....*. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x5f +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ + +char 0x60 +...*.... +....*... +.....*.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x61 +........ +........ +........ +........ +........ +.***.... +....*... +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +*...**.. +.***.**. +........ +........ + +char 0x62 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +........ +........ + +char 0x63 +........ +........ +........ +........ +........ +..**.... +.*..**.. +*....*.. +*....*.. +*....... +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x64 +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.**. +........ +........ + +char 0x65 +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +******.. +*....... +*.....*. +.*....*. +..****.. +........ +........ + +char 0x66 +....***. +...*.... +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x67 +........ +........ +........ +........ +........ +..**.**. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +.....*.. +.****... + +char 0x68 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x69 +........ +...*.... +...*.... +........ +........ +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6a +........ +.....*.. +.....*.. +........ +........ +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +....*... +....*... +..**.... + +char 0x6b +**...... +.*...... +.*...... +.*...... +.*...... +.*..***. +.*...*.. +.*..*... +.*.*.... +.**..... +.*.*.... +.*..*... +.*...*.. +***..**. +........ +........ + +char 0x6c +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6d +........ +........ +........ +........ +........ +****.**. +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +**.**.** +........ +........ + +char 0x6e +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x6f +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x70 +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +.*...... +***..... + +char 0x71 +........ +........ +........ +........ +........ +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +....***. + +char 0x72 +........ +........ +........ +........ +........ +**.***.. +.**...*. +.*....*. +.*...... +.*...... +.*...... +.*...... +.*...... +***..... +........ +........ + +char 0x73 +........ +........ +........ +........ +........ +.****.*. +*....**. +*.....*. +**...... +..***... +.....**. +*.....*. +**....*. +*.****.. +........ +........ + +char 0x74 +........ +........ +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....***. +........ +........ + +char 0x75 +........ +........ +........ +........ +........ +**...**. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...**. +..***.** +........ +........ + +char 0x76 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +........ +........ + +char 0x77 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x78 +........ +........ +........ +........ +........ +**...**. +.*...*.. +..*.*... +..*.*... +...*.... +..*.*... +..*.*... +.*...*.. +**...**. +........ +........ + +char 0x79 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...*.... +...*.... +.**..... + +char 0x7a +........ +........ +........ +........ +........ +*******. +*.....*. +*....*.. +....*... +...*.... +..*..... +.*....*. +*.....*. +*******. +........ +........ + +char 0x7b +........ +.....**. +....*... +...*.... +...*.... +...*.... +...*.... +.**..... +...*.... +...*.... +...*.... +...*.... +....*... +.....**. +........ +........ + +char 0x7c +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0x7d +........ +.**..... +...*.... +....*... +....*... +....*... +....*... +.....**. +....*... +....*... +....*... +....*... +...*.... +.**..... +........ +........ + +char 0x7e +........ +.***..*. +*...**.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x7f +........ +........ +........ +........ +...*.... +..*.*... +.*...*.. +*.....*. +*******. +*.....*. +*******. +........ +........ +........ +........ +........ + +char 0x80 +........ +..***... +.*...*.. +*.....*. +*....... +*....... +*....... +*....... +*....... +*....... +*....... +*.....*. +.*...*.. +..***... +...*.... +..*..... + +char 0x81 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x82 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x83 +........ +...*.... +..*.*... +.*...*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x84 +........ +........ +..*..*.. +..*..*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x85 +...*.... +....*... +.....*.. +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x86 +........ +...**... +..*..*.. +...**... +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x87 +........ +........ +........ +........ +........ +..****.. +.*....*. +*....... +*....... +*....... +*....... +*....... +.*....*. +..****.. +....*... +...*.... + +char 0x88 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x89 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8a +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8b +........ +........ +..*..*.. +..*..*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8c +........ +...*.... +..*.*... +.*...*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8d +...*.... +....*... +.....*.. +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8e +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x8f +........ +..***... +.*...*.. +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x90 +....**.. +....*... +...*.... +*******. +*....... +*....... +*....... +*....... +*****... +*....... +*....... +*....... +*....... +*******. +........ +........ + +char 0x91 +........ +........ +........ +........ +........ +.**..... +...***.. +...*..*. +.***..*. +*..****. +*..*.... +*..*.... +*..*..*. +.**.**.. +........ +........ + +char 0x92 +....**.. +...*.... +..*..... +..*.*... +..*.*... +..*.*... +*******. +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +........ +........ + +char 0x93 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x94 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x95 +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x96 +........ +...*.... +..*.*... +.*...*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x97 +...*.... +....*... +.....*.. +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x98 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +.*...*.. +.*...*.. +..*.*... +..*.*... +...*.... +...*.... +..*..... +..*..... +.*...... + +char 0x99 +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9a +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9b +........ +..*.*... +..*.*... +..*.*... +..****.. +.**.*.*. +*.*.*... +*.*.*... +*.*.*... +*.*.*... +*.*.*... +.**.*.*. +..****.. +..*.*... +..*.*... +..*.*... + +char 0x9c +........ +....**.. +...*..*. +..*..... +..*..... +..*..... +******.. +..*..... +..*..... +..*..... +.**..... +*.*..... +*.**..*. +.*..**.. +........ +........ + +char 0x9d +........ +*.....*. +*.....*. +.*...*.. +..*.*... +...*.... +*******. +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x9e +........ +***..... +*..*.... +*...*... +*...*... +*...*... +*..*.*.. +***..*.. +*..***** +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +........ +........ + +char 0x9f +........ +....**.. +...*..*. +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +...*.... +*..*.... +.**..... +........ +........ + +char 0xa0 +....**.. +....*... +...*.... +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0xa1 +....**.. +....*... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xa2 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa3 +....**.. +....*... +...*.... +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0xa4 +........ +...*..*. +..*.*.*. +..*..*.. +........ +*****... +*....*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0xa5 +...*..*. +..*.*.*. +..*..*.. +........ +*.....*. +**....*. +**....*. +*.*...*. +*..*..*. +*..*..*. +*...*.*. +*....**. +*....**. +*.....*. +........ +........ + +char 0xa6 +........ +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +*******. +........ +........ + +char 0xa7 +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +*******. +........ +........ + +char 0xa8 +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +..*..... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*....... +*....... +*....... +........ +........ + +char 0xaa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +......*. +......*. +......*. +........ +........ + +char 0xab +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +.****... +.....*.. +..***... +.*...... +.*****.. +........ +........ + +char 0xac +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +...**... +..*.*... +.*..*... +.*****.. +....*... +........ +........ + +char 0xad +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xae +........ +........ +........ +........ +...*..*. +..*..*.. +.*..*... +*..*.... +*..*.... +.*..*... +..*..*.. +...*..*. +........ +........ +........ +........ + +char 0xaf +........ +........ +........ +........ +*..*.... +.*..*... +..*..*.. +...*..*. +...*..*. +..*..*.. +.*..*... +*..*.... +........ +........ +........ +........ + +char 0xb0 +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. + +char 0xb1 +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. + +char 0xb2 +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* + +char 0xb3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb6 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb7 +........ +........ +........ +........ +........ +........ +........ +******.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb8 +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb9 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xba +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbb +........ +........ +........ +........ +........ +........ +........ +******.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +******.. +........ +........ +........ +........ +........ +........ + +char 0xbd +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******.. +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xbe +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +........ +........ +........ +........ +........ +........ + +char 0xbf +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc0 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc1 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc4 +........ +........ +........ +........ +........ +........ +........ +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc6 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xc8 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xc9 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xca +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xcb +........ +........ +........ +........ +........ +........ +........ +******** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcd +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xce +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcf +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xd0 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd1 +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd3 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xd5 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd6 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd8 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd9 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xda +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xdb +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdc +........ +........ +........ +........ +........ +........ +........ +........ +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdd +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... + +char 0xde +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** + +char 0xdf +******** +******** +******** +******** +******** +******** +******** +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xea +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xeb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xec +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xed +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xee +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xef +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfc +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfd +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfe +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xff +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ diff --git a/26_day/hello.nas b/26_day/hello.nas new file mode 100644 index 0000000..b4e9576 --- /dev/null +++ b/26_day/hello.nas @@ -0,0 +1,16 @@ +[INSTRSET "i486p"] +[BITS 32] + MOV ECX,msg + MOV EDX,1 +putloop: + MOV AL,[CS:ECX] + CMP AL,0 + JE fin + INT 0x40 + ADD ECX,1 + JMP putloop +fin: + MOV EDX,4 + INT 0x40 +msg: + DB "hello",0 diff --git a/26_day/hello2.nas b/26_day/hello2.nas new file mode 100644 index 0000000..5e1e58c --- /dev/null +++ b/26_day/hello2.nas @@ -0,0 +1,9 @@ +[INSTRSET "i486p"] +[BITS 32] + MOV EDX,2 + MOV EBX,msg + INT 0x40 + MOV EDX,4 + INT 0x40 +msg: + DB "hello",0 diff --git a/26_day/hello3.c b/26_day/hello3.c new file mode 100644 index 0000000..97d3236 --- /dev/null +++ b/26_day/hello3.c @@ -0,0 +1,12 @@ +void api_putchar(int c); +void api_end(void); + +void HariMain(void) +{ + api_putchar('h'); + api_putchar('e'); + api_putchar('l'); + api_putchar('l'); + api_putchar('o'); + api_end(); +} diff --git a/26_day/hello4.c b/26_day/hello4.c new file mode 100644 index 0000000..7fb73de --- /dev/null +++ b/26_day/hello4.c @@ -0,0 +1,8 @@ +void api_putstr0(char *s); +void api_end(void); + +void HariMain(void) +{ + api_putstr0("hello, world\n"); + api_end(); +} diff --git a/26_day/hello5.nas b/26_day/hello5.nas new file mode 100644 index 0000000..ee62330 --- /dev/null +++ b/26_day/hello5.nas @@ -0,0 +1,20 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "hello5.nas"] + + GLOBAL _HariMain + +[SECTION .text] + +_HariMain: + MOV EDX,2 + MOV EBX,msg + INT 0x40 + MOV EDX,4 + INT 0x40 + +[SECTION .data] + +msg: + DB "hello, world", 0x0a, 0 diff --git a/26_day/int.c b/26_day/int.c new file mode 100644 index 0000000..54c4c7a --- /dev/null +++ b/26_day/int.c @@ -0,0 +1,26 @@ +/*初始化关系 */ + +#include "bootpack.h" +#include + +void init_pic(void) +/* PIC初始化 */ +{ + io_out8(PIC0_IMR, 0xff ); /* 禁止所有中断 */ + io_out8(PIC1_IMR, 0xff ); /* 禁止所有中断 */ + + io_out8(PIC0_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC0_ICW2, 0x20 ); /* IRQ0-7由INT20-27接收 */ + io_out8(PIC0_ICW3, 1 << 2); /* PIC1由IRQ2相连 */ + io_out8(PIC0_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC1_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC1_ICW2, 0x28 ); /* IRQ8-15由INT28-2f接收 */ + io_out8(PIC1_ICW3, 2 ); /* PIC1由IRQ2连接 */ + io_out8(PIC1_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外全部禁止 */ + io_out8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中断 */ + + return; +} diff --git a/26_day/ipl10.nas b/26_day/ipl10.nas new file mode 100644 index 0000000..7108a21 --- /dev/null +++ b/26_day/ipl10.nas @@ -0,0 +1,109 @@ +; haribote-ipl +; TAB=4 + +CYLS EQU 10 ; 声明CYLS=10 + + ORG 0x7c00 ; 指明程序装载地址 + +; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code + + JMP entry + DB 0x90 + DB "HARIBOTE" ; 启动扇区名称(8字节) + DW 512 ; 每个扇区(sector)大小(必须512字节) + DB 1 ; 簇(cluster)大小(必须为1个扇区) + DW 1 ; FAT起始位置(一般为第一个扇区) + DB 2 ; FAT个数(必须为2) + DW 224 ; 根目录大小(一般为224项) + DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512) + DB 0xf0 ; 磁盘类型(必须为0xf0) + DW 9 ; FAT的长度(必??9扇区) + DW 18 ; 一个磁道(track)有几个扇区(必须为18) + DW 2 ; 磁头数(必??2) + DD 0 ; 不使用分区,必须是0 + DD 2880 ; 重写一次磁盘大小 + DB 0,0,0x29 ; 意义不明(固定) + DD 0xffffffff ; (可能是)卷标号码 + DB "HARIBOTEOS " ; 磁盘的名称(必须为11字?,不足填空格) + DB "FAT12 " ; 磁盘格式名称(必??8字?,不足填空格) + RESB 18 ; 先空出18字节 + +; 程序主体 + +entry: + MOV AX,0 ; 初始化寄存器 + MOV SS,AX + MOV SP,0x7c00 + MOV DS,AX + +; 读取磁盘 + + MOV AX,0x0820 + MOV ES,AX + MOV CH,0 ; 柱面0 + MOV DH,0 ; 磁头0 + MOV CL,2 ; 扇区2 + +readloop: + MOV SI,0 ; 记录失败次数寄存器 + +retry: + MOV AH,0x02 ; AH=0x02 : 读入磁盘 + MOV AL,1 ; 1个扇区 + MOV BX,0 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 调用磁盘BIOS + JNC next ; 没出错则跳转到fin + ADD SI,1 ; 往SI加1 + CMP SI,5 ; 比较SI与5 + JAE error ; SI >= 5 跳转到error + MOV AH,0x00 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 重置驱动器 + JMP retry +next: + MOV AX,ES ; 把内存地址后移0x200(512/16十六进制转换) + ADD AX,0x0020 + MOV ES,AX ; ADD ES,0x020因为没有ADD ES,只能通过AX进行 + ADD CL,1 ; 往CL里面加1 + CMP CL,18 ; 比较CL与18 + JBE readloop ; CL <= 18 跳转到readloop + MOV CL,1 + ADD DH,1 + CMP DH,2 + JB readloop ; DH < 2 跳转到readloop + MOV DH,0 + ADD CH,1 + CMP CH,CYLS + JB readloop ; CH < CYLS 跳转到readloop + +; 读取完毕,跳转到haribote.sys执行! + MOV [0x0ff0],CH ; IPLがどこまで読んだのかをメモ + JMP 0xc200 + +error: + MOV SI,msg + +putloop: + MOV AL,[SI] + ADD SI,1 ; 给SI加1 + CMP AL,0 + JE fin + MOV AH,0x0e ; 显示一个文字 + MOV BX,15 ; 指定字符颜色 + INT 0x10 ; 调用显卡BIOS + JMP putloop + +fin: + HLT ; 让CPU停止,等待指令 + JMP fin ; 无限循环 + +msg: + DB 0x0a, 0x0a ; 换行两次 + DB "load error" + DB 0x0a ; 换行 + DB 0 + + RESB 0x7dfe-$ ; 填写0x00直到0x001fe + + DB 0x55, 0xaa diff --git a/26_day/keyboard.c b/26_day/keyboard.c new file mode 100644 index 0000000..eb5140a --- /dev/null +++ b/26_day/keyboard.c @@ -0,0 +1,44 @@ +/* 键盘控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *keyfifo; +int keydata0; + +void inthandler21(int *esp) +{ + int data; + io_out8(PIC0_OCW2, 0x61); /* 把IRQ-01接收信号结束的信息通知给PIC */ + data = io_in8(PORT_KEYDAT); + fifo32_put(keyfifo, data + keydata0); + return; +} + +#define PORT_KEYSTA 0x0064 +#define KEYSTA_SEND_NOTREADY 0x02 +#define KEYCMD_WRITE_MODE 0x60 +#define KBC_MODE 0x47 + +void wait_KBC_sendready(void) +{ + /* 等待键盘控制电路准备完毕 */ + for (;;) { + if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) { + break; + } + } + return; +} + +void init_keyboard(struct FIFO32 *fifo, int data0) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + keyfifo = fifo; + keydata0 = data0; + /* 键盘控制器的初始化 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, KBC_MODE); + return; +} diff --git a/26_day/lines.c b/26_day/lines.c new file mode 100644 index 0000000..83e7ceb --- /dev/null +++ b/26_day/lines.c @@ -0,0 +1,29 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +void api_closewin(int win); +int api_getkey(int mode); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win, i; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "lines"); + for (i = 0; i < 8; i++) { + api_linewin(win + 1, 8, 26, 77, i * 9 + 26, i); + api_linewin(win + 1, 88, 26, i * 9 + 88, 89, i); + } + api_refreshwin(win, 6, 26, 154, 90); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_closewin(win); + api_end(); +} diff --git a/26_day/make.bat b/26_day/make.bat new file mode 100644 index 0000000..e489766 --- /dev/null +++ b/26_day/make.bat @@ -0,0 +1 @@ +..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/26_day/memory.c b/26_day/memory.c new file mode 100644 index 0000000..54a447a --- /dev/null +++ b/26_day/memory.c @@ -0,0 +1,162 @@ +/* �������֌W */ + +#include "bootpack.h" + +#define EFLAGS_AC_BIT 0x00040000 +#define CR0_CACHE_DISABLE 0x60000000 + +unsigned int memtest(unsigned int start, unsigned int end) +{ + char flg486 = 0; + unsigned int eflg, cr0, i; + + /* 确认CPU是386还是486以上的 */ + eflg = io_load_eflags(); + eflg |= EFLAGS_AC_BIT; /* AC-bit = 1 */ + io_store_eflags(eflg); + eflg = io_load_eflags(); + if ((eflg & EFLAGS_AC_BIT) != 0) { + /* 如果是386,即使设定AC=1,AC的值还会自动回到0 */ + flg486 = 1; + } + + eflg &= ~EFLAGS_AC_BIT; /* AC-bit = 0 */ + io_store_eflags(eflg); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 |= CR0_CACHE_DISABLE; /* 禁止缓存 */ + store_cr0(cr0); + } + + i = memtest_sub(start, end); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 &= ~CR0_CACHE_DISABLE; /* 允许缓存 */ + store_cr0(cr0); + } + + return i; +} + +void memman_init(struct MEMMAN *man) +{ + man->frees = 0; /* 可用信息数目 */ + man->maxfrees = 0; /* 用于观察可用状况:frees的最大值 */ + man->lostsize = 0; /* 释放失败的内存的大小总和 */ + man->losts = 0; /* 释放失败次数 */ + return; +} + +unsigned int memman_total(struct MEMMAN *man) +/* 报告空余内存大小的合计 */ +{ + unsigned int i, t = 0; + for (i = 0; i < man->frees; i++) { + t += man->free[i].size; + } + return t; +} + +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size) +/* 分配 */ +{ + unsigned int i, a; + for (i = 0; i < man->frees; i++) { + if (man->free[i].size >= size) { + /* 找到了足够大的内存 */ + a = man->free[i].addr; + man->free[i].addr += size; + man->free[i].size -= size; + if (man->free[i].size == 0) { + /* 如果free[i]变成了0,就减掉一条可用信息 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 代入结构体 */ + } + } + return a; + } + } + return 0; /* 没有可用空间 */ +} + +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size) +/* 释放 */ +{ + int i, j; + /* 为便于归纳内存,将free[]按照addr的顺序排列 */ + /* 所以,先决定应该放在哪里 */ + for (i = 0; i < man->frees; i++) { + if (man->free[i].addr > addr) { + break; + } + } + /* free[i - 1].addr < addr < free[i].addr */ + if (i > 0) { + /* 前面有可用内存 */ + if (man->free[i - 1].addr + man->free[i - 1].size == addr) { + /* 可以与前面的可用内存归纳到一起 */ + man->free[i - 1].size += size; + if (i < man->frees) { + /* 后面也有 */ + if (addr + size == man->free[i].addr) { + /* 也可以与后面的可用内存归纳到一起 */ + man->free[i - 1].size += man->free[i].size; + /* man->free[i]删除 */ + /* free[i]变成0后归纳到前面去 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 结构体赋值 */ + } + } + } + return 0; /* 成功完成 */ + } + } + /* 不能与前面的可用空间归纳到一起 */ + if (i < man->frees) { + /* 后面还有 */ + if (addr + size == man->free[i].addr) { + /* 可以与后面的内容归纳到一起 */ + man->free[i].addr = addr; + man->free[i].size += size; + return 0; /* 成功完成 */ + } + } + /* 既不能与前面归纳到一起,也不能与后面归纳到一起 */ + if (man->frees < MEMMAN_FREES) { + /* free[i]之后的,向后移动,腾出一点可用空间 */ + for (j = man->frees; j > i; j--) { + man->free[j] = man->free[j - 1]; + } + man->frees++; + if (man->maxfrees < man->frees) { + man->maxfrees = man->frees; /* 更新最大值 */ + } + man->free[i].addr = addr; + man->free[i].size = size; + return 0; /* 成功完成 */ + } + /* 不能往后移动 */ + man->losts++; + man->lostsize += size; + return -1; /* 失败 */ +} + +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size) +{ + unsigned int a; + size = (size + 0xfff) & 0xfffff000; + a = memman_alloc(man, size); + return a; +} + +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size) +{ + int i; + size = (size + 0xfff) & 0xfffff000; + i = memman_free(man, addr, size); + return i; +} diff --git a/26_day/mouse.c b/26_day/mouse.c new file mode 100644 index 0000000..0c6403e --- /dev/null +++ b/26_day/mouse.c @@ -0,0 +1,76 @@ +/* 鼠标控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *mousefifo; +int mousedata0; + +void inthandler2c(int *esp) +/* 来自PS/2鼠标的中断 */ +{ + int data; + io_out8(PIC1_OCW2, 0x64); /* 把IRQ-12接收信号结束的信息通知给PIC1 */ + io_out8(PIC0_OCW2, 0x62); /* 把IRQ-02接收信号结束的信息通知给PIC0 */ + data = io_in8(PORT_KEYDAT); + fifo32_put(mousefifo, data + mousedata0); + return; +} + +#define KEYCMD_SENDTO_MOUSE 0xd4 +#define MOUSECMD_ENABLE 0xf4 + +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + mousefifo = fifo; + mousedata0 = data0; + /* 鼠标有效 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, MOUSECMD_ENABLE); + /* 顺利的话,ACK(0xfa)会被发送*/ + mdec->phase = 0; /* 等待鼠标的0xfa的阶段*/ +return; +} + +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat) +{ + if (mdec->phase == 0) { + /* 等待鼠标的0xfa的阶段 */ + if (dat == 0xfa) { + mdec->phase = 1; + } + return 0; + } + if (mdec->phase == 1) { + /* 等待鼠标第一字节的阶段 */ + mdec->buf[0] = dat; + mdec->phase = 2; + return 0; + } + if (mdec->phase == 2) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[1] = dat; + mdec->phase = 3; + return 0; + } + if (mdec->phase == 3) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[2] = dat; + mdec->phase = 1; + mdec->btn = mdec->buf[0] & 0x07; + mdec->x = mdec->buf[1]; + mdec->y = mdec->buf[2]; + if ((mdec->buf[0] & 0x10) != 0) { + mdec->x |= 0xffffff00; + } + if ((mdec->buf[0] & 0x20) != 0) { + mdec->y |= 0xffffff00; + } + mdec->y = - mdec->y; /* 鼠标的y方向与画面符号相反 */ + return 1; + } + /* 应该不可能到这里来 */ + return -1; +} diff --git a/26_day/mtask.c b/26_day/mtask.c new file mode 100644 index 0000000..b91869d --- /dev/null +++ b/26_day/mtask.c @@ -0,0 +1,202 @@ +/* 多任务管理 */ + +#include "bootpack.h" + +struct TASKCTL *taskctl; +struct TIMER *task_timer; + +struct TASK *task_now(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + return tl->tasks[tl->now]; +} + +void task_add(struct TASK *task) +{ + struct TASKLEVEL *tl = &taskctl->level[task->level]; + tl->tasks[tl->running] = task; + tl->running++; + task->flags = 2; /*活动中*/ + return; +} + +void task_remove(struct TASK *task) +{ + int i; + struct TASKLEVEL *tl = &taskctl->level[task->level]; + + /*寻找task所在的位置*/ + for (i = 0; i < tl->running; i++) { + if (tl->tasks[i] == task) { + /*在这里 */ + break; + } + } + + tl->running--; + if (i < tl->now) { + tl->now--; /*需要移动成员,要相应地处理 */ + } + if (tl->now >= tl->running) { + /*如果now的值出现异常,则进行修正*/ + tl->now = 0; + } + task->flags = 1; /* 休眠中 */ + + /* 移动 */ + for (; i < tl->running; i++) { + tl->tasks[i] = tl->tasks[i + 1]; + } + return; +} + +void task_switchsub(void) +{ + int i; + /*寻找最上层的LEVEL */ + for (i = 0; i < MAX_TASKLEVELS; i++) { + if (taskctl->level[i].running > 0) { + break; /*找到了*/ + } + } + taskctl->now_lv = i; + taskctl->lv_change = 0; + return; +} + +void task_idle(void) +{ + for (;;) { + io_hlt(); + } +} + +struct TASK *task_init(struct MEMMAN *memman) +{ + int i; + struct TASK *task, *idle; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + + + taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL)); + for (i = 0; i < MAX_TASKS; i++) { + taskctl->tasks0[i].flags = 0; + taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8; + set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32); + } + for (i = 0; i < MAX_TASKLEVELS; i++) { + taskctl->level[i].running = 0; + taskctl->level[i].now = 0; + } + + task = task_alloc(); + task->flags = 2; /*活动中标志*/ + task->priority = 2; /* 0.02秒*/ + task->level = 0; /*最高LEVEL */ + task_add(task); + task_switchsub(); /* LEVEL 设置*/ + load_tr(task->sel); + task_timer = timer_alloc(); + timer_settime(task_timer, task->priority); + + idle = task_alloc(); + idle->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024; + idle->tss.eip = (int) &task_idle; + idle->tss.es = 1 * 8; + idle->tss.cs = 2 * 8; + idle->tss.ss = 1 * 8; + idle->tss.ds = 1 * 8; + idle->tss.fs = 1 * 8; + idle->tss.gs = 1 * 8; + task_run(idle, MAX_TASKLEVELS - 1, 1); + + return task; +} + +struct TASK *task_alloc(void) +{ + int i; + struct TASK *task; + for (i = 0; i < MAX_TASKS; i++) { + if (taskctl->tasks0[i].flags == 0) { + task = &taskctl->tasks0[i]; + task->flags = 1; /*正在使用的标志*/ + task->tss.eflags = 0x00000202; /* IF = 1; */ + task->tss.eax = 0; /*这里先置为0*/ + task->tss.ecx = 0; + task->tss.edx = 0; + task->tss.ebx = 0; + task->tss.ebp = 0; + task->tss.esi = 0; + task->tss.edi = 0; + task->tss.es = 0; + task->tss.ds = 0; + task->tss.fs = 0; + task->tss.gs = 0; + task->tss.ldtr = 0; + task->tss.iomap = 0x40000000; + task->tss.ss0 = 0; + return task; + } + } + return 0; /*全部正在使用*/ +} + +void task_run(struct TASK *task, int level, int priority) +{ + if (level < 0) { + level = task->level; /*不改变LEVEL */ + } + if (priority > 0) { + task->priority = priority; + } + if (task->flags == 2 && task->level != level) { + /*改变活动中的LEVEL */ + task_remove(task); /*这里执行之后flag的值会变为1,于是下面的if语句块也会被执行*/ + } + if (task->flags != 2) { + /*从休眠状态唤醒的情形*/ + task->level = level; + task_add(task); + } + taskctl->lv_change = 1; /*下次任务切换时检查LEVEL */ + return; +} + +void task_sleep(struct TASK *task) +{ + struct TASK *now_task; + if (task->flags == 2) { + /*如果处于活动状态*/ + now_task = task_now(); + task_remove(task); /*执行此语句的话flags将变为1 */ + if (task == now_task) { + /*如果是让自己休眠,则需要进行任务切换*/ + task_switchsub(); + now_task = task_now(); /*在设定后获取当前任务的值*/ + farjmp(0, now_task->sel); + } + } + return; +} + + +void task_switch(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + struct TASK *new_task, *now_task = tl->tasks[tl->now]; + tl->now++; + if (tl->now == tl->running) { + tl->now = 0; + } + if (taskctl->lv_change != 0) { + task_switchsub(); + tl = &taskctl->level[taskctl->now_lv]; + } + new_task = tl->tasks[tl->now]; + timer_settime(task_timer, new_task->priority); + if (new_task != now_task) { + farjmp(0, new_task->sel); + } + return; +} diff --git a/26_day/naskfunc.nas b/26_day/naskfunc.nas new file mode 100644 index 0000000..a45775d --- /dev/null +++ b/26_day/naskfunc.nas @@ -0,0 +1,291 @@ +; naskfunc +; TAB=4 + +[FORMAT "WCOFF"] ; 制作目标文件的模式 +[INSTRSET "i486p"] ; 使用到486为止的指令 +[BITS 32] ; 3制作32位模式用的机器语言 +[FILE "naskfunc.nas"] ; 文件名 + + GLOBAL _io_hlt, _io_cli, _io_sti, _io_stihlt + GLOBAL _io_in8, _io_in16, _io_in32 + GLOBAL _io_out8, _io_out16, _io_out32 + GLOBAL _io_load_eflags, _io_store_eflags + GLOBAL _load_gdtr, _load_idtr + GLOBAL _load_cr0, _store_cr0 + GLOBAL _load_tr + GLOBAL _asm_inthandler20, _asm_inthandler21 + GLOBAL _asm_inthandler2c, _asm_inthandler0c + GLOBAL _asm_inthandler0d, _asm_end_app + GLOBAL _memtest_sub + GLOBAL _farjmp, _farcall + GLOBAL _asm_hrb_api, _start_app + EXTERN _inthandler20, _inthandler21 + EXTERN _inthandler2c, _inthandler0d + EXTERN _inthandler0c + EXTERN _hrb_api + +[SECTION .text] + +_io_hlt: ; void io_hlt(void); + HLT + RET + +_io_cli: ; void io_cli(void); + CLI + RET + +_io_sti: ; void io_sti(void); + STI + RET + +_io_stihlt: ; void io_stihlt(void); + STI + HLT + RET + +_io_in8: ; int io_in8(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AL,DX + RET + +_io_in16: ; int io_in16(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AX,DX + RET + +_io_in32: ; int io_in32(int port); + MOV EDX,[ESP+4] ; port + IN EAX,DX + RET + +_io_out8: ; void io_out8(int port, int data); + MOV EDX,[ESP+4] ; port + MOV AL,[ESP+8] ; data + OUT DX,AL + RET + +_io_out16: ; void io_out16(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,AX + RET + +_io_out32: ; void io_out32(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,EAX + RET + +_io_load_eflags: ; int io_load_eflags(void); + PUSHFD ; PUSH EFLAGS + POP EAX + RET + +_io_store_eflags: ; void io_store_eflags(int eflags); + MOV EAX,[ESP+4] + PUSH EAX + POPFD ; POP EFLAGS + RET + +_load_gdtr: ; void load_gdtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LGDT [ESP+6] + RET + +_load_idtr: ; void load_idtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LIDT [ESP+6] + RET + +_load_cr0: ; int load_cr0(void); + MOV EAX,CR0 + RET + +_store_cr0: ; void store_cr0(int cr0); + MOV EAX,[ESP+4] + MOV CR0,EAX + RET + +_load_tr: ; void load_tr(int tr); + LTR [ESP+4] ; tr + RET + +_asm_inthandler20: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler20 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler21: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler21 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler2c: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler2c + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler0c: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0c + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; 在INT 0x0c中也需要这句 + IRETD + +_asm_inthandler0d: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0d + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; INT 0x0d需要这句 + IRETD + +_memtest_sub: ; unsigned int memtest_sub(unsigned int start, unsigned int end) + PUSH EDI ; (由于还要使用EBX, ESI, EDI) + PUSH ESI + PUSH EBX + MOV ESI,0xaa55aa55 ; pat0 = 0xaa55aa55; + MOV EDI,0x55aa55aa ; pat1 = 0x55aa55aa; + MOV EAX,[ESP+12+4] ; i = start; +mts_loop: + MOV EBX,EAX + ADD EBX,0xffc ; p = i + 0xffc; + MOV EDX,[EBX] ; old = *p; + MOV [EBX],ESI ; *p = pat0; + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP EDI,[EBX] ; if (*p != pat1) goto fin; + JNE mts_fin + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP ESI,[EBX] ; if (*p != pat0) goto fin; + JNE mts_fin + MOV [EBX],EDX ; *p = old; + ADD EAX,0x1000 ; i += 0x1000; + CMP EAX,[ESP+12+8] ; if (i <= end) goto mts_loop; + JBE mts_loop + POP EBX + POP ESI + POP EDI + RET +mts_fin: + MOV [EBX],EDX ; *p = old; + POP EBX + POP ESI + POP EDI + RET + +_farjmp: ; void farjmp(int eip, int cs); + JMP FAR [ESP+4] ; eip, cs + RET + +_farcall: ; void farcall(int eip, int cs); + CALL FAR [ESP+4] ; eip, cs + RET + +_asm_hrb_api: + STI + PUSH DS + PUSH ES + PUSHAD ; 用于保存的PUSH + PUSHAD ; 用于向hrb_api传值的PUSH + MOV AX,SS + MOV DS,AX ; 将操作系统用段地址存入DS和ES + MOV ES,AX + CALL _hrb_api + CMP EAX,0 ; 当EAX不为0时程序结束 + JNE _asm_end_app + ADD ESP,32 + POPAD + POP ES + POP DS + IRETD +_asm_end_app: +; EAX为tss.esp0的地址 + MOV ESP,[EAX] + MOV DWORD [EAX+4],0 + POPAD + RET ; 返回cmd_app + +_start_app: ; void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); + PUSHAD ; 将32位寄存器的值全部保存起来 + MOV EAX,[ESP+36] ; 应用程序用EIP + MOV ECX,[ESP+40] ; 应用程序用CS + MOV EDX,[ESP+44] ; 应用程序用ESP + MOV EBX,[ESP+48] ; 应用程序用DS/SS + MOV EBP,[ESP+52] ; tss.esp0的地址 + MOV [EBP ],ESP ; 保存操作系统用ESP + MOV [EBP+4],SS ; 保存操作系统用SS + MOV ES,BX + MOV DS,BX + MOV FS,BX + MOV GS,BX +; 下面调整栈,以免用RETF跳转到应用程序 + OR ECX,3 ; 将应用程序用段号和3进行OR运算 + OR EBX,3 ; 将应用程序用段号和3进行OR运算 + PUSH EBX ; 应用程序的SS + PUSH EDX ; 应用程序的ESP + PUSH ECX ; 应用程序的CS + PUSH EAX ; 应用程序的EIP + RETF +; 应用程序结束后不会回到这里 diff --git a/26_day/noodle.c b/26_day/noodle.c new file mode 100644 index 0000000..13b9033 --- /dev/null +++ b/26_day/noodle.c @@ -0,0 +1,42 @@ +#include + +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +int api_getkey(int mode); +int api_alloctimer(void); +void api_inittimer(int timer, int data); +void api_settimer(int timer, int time); +void api_end(void); + +void HariMain(void) +{ + char *buf, s[12]; + int win, timer, sec = 0, min = 0, hou = 0; + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "noodle"); + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (;;) { + sprintf(s, "%5d:%02d:%02d", hou, min, sec); + api_boxfilwin(win, 28, 27, 115, 41, 7);/*白色*/ + api_putstrwin(win, 28, 27, 0, 11, s); /*黑色*/ + api_settimer(timer, 100); /* 1秒 */ + if (api_getkey(1) != 128) { + break; + } + sec++; + if (sec == 60) { + sec = 0; + min++; + if (min == 60) { + min = 0; + hou++; + } + } + } + api_end(); +} diff --git a/26_day/sheet.c b/26_day/sheet.c new file mode 100644 index 0000000..a51c756 --- /dev/null +++ b/26_day/sheet.c @@ -0,0 +1,217 @@ +/* sheet */ + +#include "bootpack.h" + +#define SHEET_USE 1 + +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize) +{ + struct SHTCTL *ctl; + int i; + ctl = (struct SHTCTL *) memman_alloc_4k(memman, sizeof (struct SHTCTL)); + if (ctl == 0) { + goto err; + } + ctl->map = (unsigned char *) memman_alloc_4k(memman, xsize * ysize); + if (ctl->map == 0) { + memman_free_4k(memman, (int) ctl, sizeof (struct SHTCTL)); + goto err; + } + ctl->vram = vram; + ctl->xsize = xsize; + ctl->ysize = ysize; + ctl->top = -1; /* 没有一张SHEET */ + for (i = 0; i < MAX_SHEETS; i++) { + ctl->sheets0[i].flags = 0; /* 标记为未使用 */ + ctl->sheets0[i].ctl = ctl; /* 记录所属*/ + } +err: + return ctl; +} + +struct SHEET *sheet_alloc(struct SHTCTL *ctl) +{ + struct SHEET *sht; + int i; + for (i = 0; i < MAX_SHEETS; i++) { + if (ctl->sheets0[i].flags == 0) { + sht = &ctl->sheets0[i]; + sht->flags = SHEET_USE; /* 标记为正在使用*/ + sht->height = -1; /* 隐藏 */ + sht->task = 0; /*不使用自动关闭功能*/ + return sht; + } + } + return 0; /* 所有的SHEET都处于正在使用状态*/ +} + +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv) +{ + sht->buf = buf; + sht->bxsize = xsize; + sht->bysize = ysize; + sht->col_inv = col_inv; + return; +} + +void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1; + unsigned char *buf, sid, *map = ctl->map; + struct SHEET *sht; + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= ctl->top; h++) { + sht = ctl->sheets[h]; + sid = sht - ctl->sheets0; /* 将进行了减法计算的地址作为图层号码使用 */ + buf = sht->buf; + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } + if (by1 > sht->bysize) { by1 = sht->bysize; } + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (buf[by * sht->bxsize + bx] != sht->col_inv) { + map[vy * ctl->xsize + vx] = sid; + } + } + } + } + return; +} + +void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0, int h1) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1; + unsigned char *buf, *vram = ctl->vram, *map = ctl->map, sid; + struct SHEET *sht; + + /* 如果refresh的范围超出了画面则修正 */ + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= h1; h++) { + sht = ctl->sheets[h]; + buf = sht->buf; + sid = sht - ctl->sheets0; + + /* 使用vx0~vy1,对bx0~by1进行倒推 */ + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } /* 处理刷新范围在图层外侧 */ + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } /* 应对不同的重叠方式 */ + if (by1 > sht->bysize) { by1 = sht->bysize; } + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + } + } + return; +} + +void sheet_updown(struct SHEET *sht, int height) +{ + struct SHTCTL *ctl = sht->ctl; + int h, old = sht->height; /* 存储设置前的高度信息 */ + if (height > ctl->top + 1) { + height = ctl->top + 1; + } + if (height < -1) { + height = -1; + } + sht->height = height;/* 设定高度 */ + + /* 下面主要是进行sheets[]的重新排列 */ + if (old > height) { /* 比以前低 */ + if (height >= 0) { + /* 把中间的往上提 */ + for (h = old; h > height; h--) { + ctl->sheets[h] = ctl->sheets[h - 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1, old); + } else { /* 隐藏 */ + if (ctl->top > old) { + /* 把上面的降下来 */ + for (h = old; h < ctl->top; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + } + ctl->top--; /* 由于显示中的图层减少了一个,所以最上面的图层高度下降 */ + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0, old - 1); + } + } else if (old < height) { /* 比以前高 */ + if (old >= 0) { + /* 把中间的拉下去 */ + for (h = old; h < height; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + } else { /* 由隐藏状态转为显示状态 */ + /* 将已在上面的提上来 */ + for (h = ctl->top; h >= height; h--) { + ctl->sheets[h + 1] = ctl->sheets[h]; + ctl->sheets[h + 1]->height = h + 1; + } + ctl->sheets[height] = sht; + ctl->top++; /* 由于已显示的图层增加了1个,所以最上面的图层高度增加 */ + } + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height, height); /* 按新图层信息重新绘制画面 */ + } + return; +} + +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1) +{ + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面*/ + sheet_refreshsub(sht->ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1, sht->height, sht->height); + } + return; +} + +void sheet_slide(struct SHEET *sht, int vx0, int vy0) +{ + struct SHTCTL *ctl = sht->ctl; + int old_vx0 = sht->vx0, old_vy0 = sht->vy0; + sht->vx0 = vx0; + sht->vy0 = vy0; + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面 */ + sheet_refreshmap(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0); + sheet_refreshmap(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height); + sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0, sht->height - 1); + sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height, sht->height); + } + return; +} + +void sheet_free(struct SHEET *sht) +{ + if (sht->height >= 0) { + sheet_updown(sht, -1); /* 如果处于显示状态,则先设定为隐藏 */ + } + sht->flags = 0; /* "未使用"标志 */ + return; +} diff --git a/26_day/star1.c b/26_day/star1.c new file mode 100644 index 0000000..8d80ffa --- /dev/null +++ b/26_day/star1.c @@ -0,0 +1,18 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_point(int win, int x, int y, int col); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "star1"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + api_point(win, 75, 59, 3);/*黄色*/ + api_end(); +} diff --git a/26_day/stars.c b/26_day/stars.c new file mode 100644 index 0000000..dc38b2b --- /dev/null +++ b/26_day/stars.c @@ -0,0 +1,24 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_point(int win, int x, int y, int col); +void api_end(void); + +int rand(void); /*产生0~32767之间的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win, x, y, 3);/*黄色*/ + } + api_end(); +} diff --git a/26_day/stars2.c b/26_day/stars2.c new file mode 100644 index 0000000..94a029e --- /dev/null +++ b/26_day/stars2.c @@ -0,0 +1,26 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_point(int win, int x, int y, int col); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_end(void); + +int rand(void); /*产生0~32767的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars2"); + api_boxfilwin(win + 1, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win + 1, x, y, 3);/*黄色*/ + } + api_refreshwin(win, 6, 26, 144, 94); + api_end(); +} diff --git a/26_day/timer.c b/26_day/timer.c new file mode 100644 index 0000000..9018ac8 --- /dev/null +++ b/26_day/timer.c @@ -0,0 +1,169 @@ +/* 定时器 */ + +#include "bootpack.h" + +#define PIT_CTRL 0x0043 +#define PIT_CNT0 0x0040 + +struct TIMERCTL timerctl; + +#define TIMER_FLAGS_ALLOC 1 /* 已配置状态 */ +#define TIMER_FLAGS_USING 2 /* 定时器运行中 */ + +void init_pit(void) +{ + int i; + struct TIMER *t; + io_out8(PIT_CTRL, 0x34); + io_out8(PIT_CNT0, 0x9c); + io_out8(PIT_CNT0, 0x2e); + timerctl.count = 0; + for (i = 0; i < MAX_TIMER; i++) { + timerctl.timers0[i].flags = 0; /* 没有使用 */ + } + t = timer_alloc(); /* 取得一个 */ + t->timeout = 0xffffffff; + t->flags = TIMER_FLAGS_USING; + t->next = 0; /* 末尾 */ + timerctl.t0 = t; /* 因为现在只有哨兵,所以他就在最前面*/ + timerctl.next = 0xffffffff; /* 因为只有哨兵,所以下一个超时时刻就是哨兵的时刻 */ + return; +} + +struct TIMER *timer_alloc(void) +{ + int i; + for (i = 0; i < MAX_TIMER; i++) { + if (timerctl.timers0[i].flags == 0) { + timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; + timerctl.timers0[i].flags2 = 0; + return &timerctl.timers0[i]; + } + } + return 0; /* 没找到 */ +} + +void timer_free(struct TIMER *timer) +{ + timer->flags = 0; /* 未使用 */ + return; +} + +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data) +{ + timer->fifo = fifo; + timer->data = data; + return; +} + +void timer_settime(struct TIMER *timer, unsigned int timeout) +{ + int e; + struct TIMER *t, *s; + timer->timeout = timeout + timerctl.count; + timer->flags = TIMER_FLAGS_USING; + e = io_load_eflags(); + io_cli(); + t = timerctl.t0; + if (timer->timeout <= t->timeout) { + /* 插入最前面的情况 */ + timerctl.t0 = timer; + timer->next = t; /* 下面是设定t */ + timerctl.next = timer->timeout; + io_store_eflags(e); + return; + } + for (;;) { + s = t; + t = t->next; + if (timer->timeout <= t->timeout) { + /* 插入s和t之间的情况 */ + s->next = timer; /* s下一个是timer */ + timer->next = t; /* timer的下一个是t */ + io_store_eflags(e); + return; + } + } +} + +void inthandler20(int *esp) +{ + struct TIMER *timer; + char ts = 0; + io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00接收信号结束的信息通知给PIC */ + timerctl.count++; + if (timerctl.next > timerctl.count) { + return; + } + timer = timerctl.t0; /* 首先把最前面的地址赋给timer */ + for (;;) { + /* 因为timers的定时器都处于运行状态,所以不确认flags */ + if (timer->timeout > timerctl.count) { + break; + } + /* 超时 */ + timer->flags = TIMER_FLAGS_ALLOC; + if (timer != task_timer) { + fifo32_put(timer->fifo, timer->data); + } else { + ts = 1; /* mt_timer超时*/ + } + timer = timer->next; /* 将下一个定时器的地址赋给timer*/ + } + timerctl.t0 = timer; + timerctl.next = timer->timeout; + if (ts != 0) { + task_switch(); + } + return; +} + +int timer_cancel(struct TIMER *timer) +{ + int e; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + if (timer->flags == TIMER_FLAGS_USING) { /*是否需要取消?*/ + if (timer == timerctl.t0) { + /*第一个定时器的取消处理*/ + t = timer->next; + timerctl.t0 = t; + timerctl.next = t->timeout; + } else { + /*非第一个定时器的取消处理*/ + /*找到timer前一个定时器*/ + t = timerctl.t0; + for (;;) { + if (t->next == timer) { + break; + } + t = t->next; + } + t->next = timer->next; + /*将之前“timer的下一个”指向“timer的下一个”*/ + } + timer->flags = TIMER_FLAGS_ALLOC; + io_store_eflags(e); + return 1; /*取消处理成功*/ + } + io_store_eflags(e); + return 0; /*不需要取消处理*/ +} + +void timer_cancelall(struct FIFO32 *fifo) +{ + int e, i; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + for (i = 0; i < MAX_TIMER; i++) { + t = &timerctl.timers0[i]; + if (t->flags != 0 && t->flags2 != 0 && t->fifo == fifo) { + timer_cancel(t); + timer_free(t); + } + } + io_store_eflags(e); + return; +} diff --git a/26_day/walk.c b/26_day/walk.c new file mode 100644 index 0000000..6b106b4 --- /dev/null +++ b/26_day/walk.c @@ -0,0 +1,35 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +void api_closewin(int win); +int api_getkey(int mode); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "walk"); + api_boxfilwin(win, 4, 24, 155, 95, 0);/*黑色*/ + x = 76; + y = 56; + api_putstrwin(win, x, y, 3, 1, "*");/*黄色*/ + for (;;) { + i = api_getkey(1); + api_putstrwin(win, x, y, 0 , 1, "*"); /*用黑色擦除*/ + if (i == '4' && x > 4) { x -= 8; } + if (i == '6' && x < 148) { x += 8; } + if (i == '8' && y > 24) { y -= 8; } + if (i == '2' && y < 80) { y += 8; } + if (i == 0x0a) { break; } /*按回车键结束*/ + api_putstrwin(win, x, y, 3 , 1, "*");/*黄色*/ + } + api_closewin(win); + api_end(); +} diff --git a/26_day/window.c b/26_day/window.c new file mode 100644 index 0000000..4d70578 --- /dev/null +++ b/26_day/window.c @@ -0,0 +1,118 @@ +/* 窗口相关函数 */ + +#include "bootpack.h" + +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act) +{ + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, xsize - 1, 0 ); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, xsize - 2, 1 ); + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, 0, ysize - 1); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, 1, ysize - 2); + boxfill8(buf, xsize, COL8_848484, xsize - 2, 1, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, xsize - 1, 0, xsize - 1, ysize - 1); + boxfill8(buf, xsize, COL8_C6C6C6, 2, 2, xsize - 3, ysize - 3); + boxfill8(buf, xsize, COL8_848484, 1, ysize - 2, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, 0, ysize - 1, xsize - 1, ysize - 1); + make_wtitle8(buf, xsize, title, act); + return; +} + +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act) +{ + static char closebtn[14][16] = { + "OOOOOOOOOOOOOOO@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQQQ@@QQQQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "O$$$$$$$$$$$$$$@", + "@@@@@@@@@@@@@@@@" + }; + int x, y; + char c, tc, tbc; + if (act != 0) { + tc = COL8_FFFFFF; + tbc = COL8_000084; + } else { + tc = COL8_C6C6C6; + tbc = COL8_848484; + } + boxfill8(buf, xsize, tbc, 3, 3, xsize - 4, 20); + putfonts8_asc(buf, xsize, 24, 4, tc, title); + for (y = 0; y < 14; y++) { + for (x = 0; x < 16; x++) { + c = closebtn[y][x]; + if (c == '@') { + c = COL8_000000; + } else if (c == '$') { + c = COL8_848484; + } else if (c == 'Q') { + c = COL8_C6C6C6; + } else { + c = COL8_FFFFFF; + } + buf[(5 + y) * xsize + (xsize - 21 + x)] = c; + } + } + return; +} + +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l) +{ + boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15); + putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); + sheet_refresh(sht, x, y, x + l * 8, y + 16); + return; +} + +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c) +{ + int x1 = x0 + sx, y1 = y0 + sy; + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3); + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1); + boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0); + return; +} + +void change_wtitle8(struct SHEET *sht, char act) +{ + int x, y, xsize = sht->bxsize; + char c, tc_new, tbc_new, tc_old, tbc_old, *buf = sht->buf; + if (act != 0) { + tc_new = COL8_FFFFFF; + tbc_new = COL8_000084; + tc_old = COL8_C6C6C6; + tbc_old = COL8_848484; + } else { + tc_new = COL8_C6C6C6; + tbc_new = COL8_848484; + tc_old = COL8_FFFFFF; + tbc_old = COL8_000084; + } + for (y = 3; y <= 20; y++) { + for (x = 3; x <= xsize - 4; x++) { + c = buf[y * xsize + x]; + if (c == tc_old && x <= xsize - 22) { + c = tc_new; + } else if (c == tbc_old) { + c = tbc_new; + } + buf[y * xsize + x] = c; + } + } + sheet_refresh(sht, 3, 3, xsize, 21); + return; +} diff --git a/26_day/winhelo.c b/26_day/winhelo.c new file mode 100644 index 0000000..6d7fb0a --- /dev/null +++ b/26_day/winhelo.c @@ -0,0 +1,11 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_end(void); + +char buf[150 * 50]; + +void HariMain(void) +{ + int win; + win = api_openwin(buf, 150, 50, -1, "hello"); + api_end(); +} diff --git a/26_day/winhelo2.c b/26_day/winhelo2.c new file mode 100644 index 0000000..f00b007 --- /dev/null +++ b/26_day/winhelo2.c @@ -0,0 +1,15 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_end(void); + +char buf[150 * 50]; + +void HariMain(void) +{ + int win; + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 3); /*黄色*/ + api_putstrwin(win, 28, 28, 0 /*黑色*/, 12, "hello, world"); + api_end(); +} diff --git a/26_day/winhelo3.c b/26_day/winhelo3.c new file mode 100644 index 0000000..527ec01 --- /dev/null +++ b/26_day/winhelo3.c @@ -0,0 +1,19 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win; + + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 6); /*浅蓝色*/ + api_putstrwin(win, 28, 28, 0 , 12, "hello, world");/*黑色*/ + api_end(); +} \ No newline at end of file From 95dcc1402599690d4bbd3f55b1651efb5422cc97 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Mon, 16 May 2016 10:54:13 +0800 Subject: [PATCH 25/83] =?UTF-8?q?=E6=8F=90=E9=AB=98=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E9=80=9F=E5=BA=A6=EF=BC=881=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 26_day/sheet.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/26_day/sheet.c b/26_day/sheet.c index a51c756..eb2a10b 100644 --- a/26_day/sheet.c +++ b/26_day/sheet.c @@ -75,14 +75,26 @@ void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, in if (by0 < 0) { by0 = 0; } if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } if (by1 > sht->bysize) { by1 = sht->bysize; } - for (by = by0; by < by1; by++) { - vy = sht->vy0 + by; - for (bx = bx0; bx < bx1; bx++) { - vx = sht->vx0 + bx; - if (buf[by * sht->bxsize + bx] != sht->col_inv) { + if (sht->col_inv == -1) { + /*无透明色图层专用的高速版*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; map[vy * ctl->xsize + vx] = sid; } } + } else { + /*有透明色图层用的普通版*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (buf[by * sht->bxsize + bx] != sht->col_inv) { + map[vy * ctl->xsize + vx] = sid; + } + } + } } } return; From 883213696ffee371289e949b7e4e988d69521764 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Mon, 16 May 2016 11:04:04 +0800 Subject: [PATCH 26/83] =?UTF-8?q?=E6=8F=90=E9=AB=98=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E9=80=9F=E5=BA=A6=EF=BC=882=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 26_day/bootpack.c | 8 ++++---- 26_day/console.c | 2 +- 26_day/sheet.c | 28 +++++++++++++++++++++------- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/26_day/bootpack.c b/26_day/bootpack.c index d2aa307..591cf5e 100644 --- a/26_day/bootpack.c +++ b/26_day/bootpack.c @@ -43,7 +43,7 @@ void HariMain(void) 0, 0, 0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, '|', 0, 0 }; int key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; - int j, x, y, mmx = -1, mmy = -1; + int j, x, y, mmx = -1, mmy = -1, mmx2 = 0; struct SHEET *sht = 0, *key_win; init_gdtidt(); @@ -252,6 +252,7 @@ void HariMain(void) if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) { mmx = mx; /*进入窗口移动模式*/ mmy = my; + mmx2 = sht->vx0; } if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <= y && y < 19) { /*点击“×”按钮*/ @@ -272,9 +273,8 @@ void HariMain(void) /*如果处于窗口移动模式*/ x = mx - mmx; /*计算鼠标的移动距离*/ y = my - mmy; - sheet_slide(sht, sht->vx0 + x, sht->vy0 + y); - mmx = mx; /*更新为移动后的坐标*/ - mmy = my; + sheet_slide(sht, (mmx2 + x + 2) & ~3, sht->vy0 + y); + mmy = my; /*更新到移动后的坐标*/ } } else { /*没有按下左键*/ diff --git a/26_day/console.c b/26_day/console.c index 7df9bea..1b39bc1 100644 --- a/26_day/console.c +++ b/26_day/console.c @@ -347,7 +347,7 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int sht->flags |= 0x10; sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax); make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0); - sheet_slide(sht, (shtctl->xsize - esi) / 2, (shtctl->ysize - edi) / 2); + sheet_slide(sht, ((shtctl->xsize - esi) / 2) & ~3, (shtctl->ysize - edi) / 2); sheet_updown(sht, shtctl->top); /*将窗口图层高度指定为当前鼠标所在图层的高度,鼠标移到上层*/ reg[7] = (int) sht; } else if (edx == 6) { diff --git a/26_day/sheet.c b/26_day/sheet.c index eb2a10b..8c822e0 100644 --- a/26_day/sheet.c +++ b/26_day/sheet.c @@ -56,7 +56,7 @@ void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, i void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0) { - int h, bx, by, vx, vy, bx0, by0, bx1, by1; + int h, bx, by, vx, vy, bx0, by0, bx1, by1, sid4, *p;; unsigned char *buf, sid, *map = ctl->map; struct SHEET *sht; if (vx0 < 0) { vx0 = 0; } @@ -76,12 +76,26 @@ void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, in if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } if (by1 > sht->bysize) { by1 = sht->bysize; } if (sht->col_inv == -1) { - /*无透明色图层专用的高速版*/ - for (by = by0; by < by1; by++) { - vy = sht->vy0 + by; - for (bx = bx0; bx < bx1; bx++) { - vx = sht->vx0 + bx; - map[vy * ctl->xsize + vx] = sid; + if ((sht->vx0 & 3) == 0 && (bx0 & 3) == 0 && (bx1 & 3) == 0) { + /*无透明色图层专用的高速版(4字节型)*/ + bx1 = (bx1 - bx0) / 4; /* MOV次数*/ + sid4 = sid | sid << 8 | sid << 16 | sid << 24; + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + vx = sht->vx0 + bx0; + p = (int *) &map[vy * ctl->xsize + vx]; + for (bx = 0; bx < bx1; bx++) { + p[bx] = sid4; + } + } + } else { + /*无透明色图层专用的高速版(1字节型)*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + map[vy * ctl->xsize + vx] = sid; + } } } } else { From 68781eba2adf7ba2f41c69febc35f0118bb32520 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Mon, 16 May 2016 11:25:47 +0800 Subject: [PATCH 27/83] =?UTF-8?q?=E6=8F=90=E9=AB=98=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E9=80=9F=E5=BA=A6=EF=BC=883=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 26_day/sheet.c | 63 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/26_day/sheet.c b/26_day/sheet.c index 8c822e0..14aa0ea 100644 --- a/26_day/sheet.c +++ b/26_day/sheet.c @@ -116,7 +116,7 @@ void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, in void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0, int h1) { - int h, bx, by, vx, vy, bx0, by0, bx1, by1; + int h, bx, by, vx, vy, bx0, by0, bx1, by1, bx2, sid4, i, i1, *p, *q, *r; unsigned char *buf, *vram = ctl->vram, *map = ctl->map, sid; struct SHEET *sht; @@ -139,12 +139,63 @@ void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, in if (by0 < 0) { by0 = 0; } if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } /* 应对不同的重叠方式 */ if (by1 > sht->bysize) { by1 = sht->bysize; } - for (by = by0; by < by1; by++) { - vy = sht->vy0 + by; - for (bx = bx0; bx < bx1; bx++) { + if ((sht->vx0 & 3) == 0) { + /* 4字节型*/ + i = (bx0 + 3) / 4; /* bx0除以4(小数进位)*/ + i1 = bx1 / 4; /* bx1除以4(小数舍去)*/ + i1 = i1 - i; + sid4 = sid | sid << 8 | sid << 16 | sid << 24; + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1 && (bx & 3) != 0; bx++) { + /*前面被4除多余的部分逐个字节写入*/ + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } vx = sht->vx0 + bx; - if (map[vy * ctl->xsize + vx] == sid) { - vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + p = (int *) &map[vy * ctl->xsize + vx]; + q = (int *) &vram[vy * ctl->xsize + vx]; + r = (int *) &buf[by * sht->bxsize + bx]; + for (i = 0; i < i1; i++) { + /* 4的倍数部分*/ + if (p[i] == sid4) { + q[i] = r[i]; /*估计大多数会是这种情况,因此速度会变快*/ + } else { + bx2 = bx + i * 4; + vx = sht->vx0 + bx2; + if (map[vy * ctl->xsize + vx + 0] == sid) { + vram[vy * ctl->xsize + vx + 0] = buf[by * sht->bxsize + bx2 + 0]; + } + if (map[vy * ctl->xsize + vx + 1] == sid) { + vram[vy * ctl->xsize + vx + 1] = buf[by * sht->bxsize + bx2 + 1]; + } + if (map[vy * ctl->xsize + vx + 2] == sid) { + vram[vy * ctl->xsize + vx + 2] = buf[by * sht->bxsize + bx2 + 2]; + } + if (map[vy * ctl->xsize + vx + 3] == sid) { + vram[vy * ctl->xsize + vx + 3] = buf[by * sht->bxsize + bx2 + 3]; + } + } + } + for (bx += i1 * 4; bx < bx1; bx++) { + /*后面被4除多余的部分逐个字节写入*/ + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + } + } else { + /* 1字节型*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } } } } From e4a94836dddbccd3eea4ad6a4f6984eb0831bec0 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Mon, 16 May 2016 11:29:54 +0800 Subject: [PATCH 28/83] bug fix --- 25_day/bootpack.c | 2 +- 26_day/bootpack.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/25_day/bootpack.c b/25_day/bootpack.c index d2aa307..cbf766d 100644 --- a/25_day/bootpack.c +++ b/25_day/bootpack.c @@ -124,7 +124,7 @@ void HariMain(void) for (;;) { if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0) { - /* �L�[�{�[�h�R���g���[���ɑ���f�[�^������΁A���� */ + /* 如果存在向键盘控制器发送的数据,则发送它 */ keycmd_wait = fifo32_get(&keycmd); wait_KBC_sendready(); io_out8(PORT_KEYDAT, keycmd_wait); diff --git a/26_day/bootpack.c b/26_day/bootpack.c index 591cf5e..0ebdc8e 100644 --- a/26_day/bootpack.c +++ b/26_day/bootpack.c @@ -124,7 +124,7 @@ void HariMain(void) for (;;) { if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0) { - /* �L�[�{�[�h�R���g���[���ɑ���f�[�^������΁A���� */ + /* 如果存在向键盘控制器发送的数据,则发送它 */ keycmd_wait = fifo32_get(&keycmd); wait_KBC_sendready(); io_out8(PORT_KEYDAT, keycmd_wait); From d2fc0dc0f53dc7d87ea7caf405a49aec864c989b Mon Sep 17 00:00:00 2001 From: Yourtion Date: Mon, 16 May 2016 11:34:29 +0800 Subject: [PATCH 29/83] =?UTF-8?q?=E6=8F=90=E9=AB=98=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E9=80=9F=E5=BA=A6=EF=BC=884=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 26_day/bootpack.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/26_day/bootpack.c b/26_day/bootpack.c index 0ebdc8e..fe80698 100644 --- a/26_day/bootpack.c +++ b/26_day/bootpack.c @@ -15,7 +15,7 @@ void HariMain(void) char s[40]; struct FIFO32 fifo, keycmd; int fifobuf[128], keycmd_buf[32], *cons_fifo[2]; - int mx, my, i; + int mx, my, i, new_mx = -1, new_my = 0, new_wx = 0x7fffffff, new_wy = 0; unsigned int memtotal; struct MOUSE_DEC mdec; struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; @@ -131,8 +131,19 @@ void HariMain(void) } io_cli(); if (fifo32_status(&fifo) == 0) { - task_sleep(task_a); - io_sti(); + /* FIFO为空,当存在搁置的绘图操作时立即执行*/ + if (new_mx >= 0) { + io_sti(); + sheet_slide(sht_mouse, new_mx, new_my); + new_mx = -1; + } else if (new_wx != 0x7fffffff) { + io_sti(); + sheet_slide(sht, new_wx, new_wy); + new_wx = 0x7fffffff; + } else { + task_sleep(task_a); + io_sti(); + } } else { i = fifo32_get(&fifo); io_sti(); @@ -232,7 +243,8 @@ void HariMain(void) if (my > binfo->scrny - 1) { my = binfo->scrny - 1; } - sheet_slide(sht_mouse, mx, my);/* 包含sheet_refresh含sheet_refresh */ + new_mx = mx; + new_my = my; if ((mdec.btn & 0x01) != 0) { /* 按下左键 */ if (mmx < 0) { /*如果处于通常模式*/ @@ -253,6 +265,7 @@ void HariMain(void) mmx = mx; /*进入窗口移动模式*/ mmy = my; mmx2 = sht->vx0; + new_wy = sht->vy0; } if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <= y && y < 19) { /*点击“×”按钮*/ @@ -271,14 +284,19 @@ void HariMain(void) } } else { /*如果处于窗口移动模式*/ - x = mx - mmx; /*计算鼠标的移动距离*/ + x = mx - mmx; /*计算鼠标指针移动量*/ y = my - mmy; - sheet_slide(sht, (mmx2 + x + 2) & ~3, sht->vy0 + y); - mmy = my; /*更新到移动后的坐标*/ + new_wx = (mmx2 + x + 2) & ~3; + new_wy = new_wy + y; + mmy = my; } } else { /*没有按下左键*/ - mmx = -1; /*返回通常模式*/ + mmx = -1; /*切换到一般模式*/ + if (new_wx != 0x7fffffff) { + sheet_slide(sht, new_wx, new_wy); /*固定图层位置*/ + new_wx = 0x7fffffff; + } } } } From 935af85346fea7ffcd05a2e770df6cb658ecd04f Mon Sep 17 00:00:00 2001 From: Yourtion Date: Mon, 16 May 2016 11:42:37 +0800 Subject: [PATCH 30/83] =?UTF-8?q?=E5=90=AF=E5=8A=A8=E6=97=B6=E5=8F=AA?= =?UTF-8?q?=E6=89=93=E5=BC=80=E4=B8=80=E4=B8=AA=E5=91=BD=E4=BB=A4=E8=A1=8C?= =?UTF-8?q?=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 26_day/bootpack.c | 74 ++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/26_day/bootpack.c b/26_day/bootpack.c index fe80698..abada65 100644 --- a/26_day/bootpack.c +++ b/26_day/bootpack.c @@ -7,6 +7,7 @@ void keywin_off(struct SHEET *key_win); void keywin_on(struct SHEET *key_win); +struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal); void HariMain(void) { @@ -76,29 +77,8 @@ void HariMain(void) init_screen8(buf_back, binfo->scrnx, binfo->scrny); /* sht_cons */ - for (i = 0; i < 2; i++) { - sht_cons[i] = sheet_alloc(shtctl); - buf_cons[i] = (unsigned char *) memman_alloc_4k(memman, 256 * 165); - sheet_setbuf(sht_cons[i], buf_cons[i], 256, 165, -1); /*没有透明色*/ - make_window8(buf_cons[i], 256, 165, "console", 0); - make_textbox8(sht_cons[i], 8, 28, 240, 128, COL8_000000); - task_cons[i] = task_alloc(); - task_cons[i]->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 12; - task_cons[i]->tss.eip = (int) &console_task; - task_cons[i]->tss.es = 1 * 8; - task_cons[i]->tss.cs = 2 * 8; - task_cons[i]->tss.ss = 1 * 8; - task_cons[i]->tss.ds = 1 * 8; - task_cons[i]->tss.fs = 1 * 8; - task_cons[i]->tss.gs = 1 * 8; - *((int *) (task_cons[i]->tss.esp + 4)) = (int) sht_cons[i]; - *((int *) (task_cons[i]->tss.esp + 8)) = memtotal; - task_run(task_cons[i], 2, 2); /* level=2, priority=2 */ - sht_cons[i]->task = task_cons[i]; - sht_cons[i]->flags |= 0x20; /*有光标*/ - cons_fifo[i] = (int *) memman_alloc_4k(memman, 128 * 4); - fifo32_init(&task_cons[i]->fifo, 128, cons_fifo[i], task_cons[i]); - } + sht_cons[0] = open_console(shtctl, memtotal); + sht_cons[1] = 0; /* sht_mouse */ sht_mouse = sheet_alloc(shtctl); @@ -107,14 +87,12 @@ void HariMain(void) mx = (binfo->scrnx - 16) / 2; /* 计算坐标使其位于画面中央 */ my = (binfo->scrny - 28 - 16) / 2; - sheet_slide(sht_back, 0, 0); - sheet_slide(sht_cons[1], 56, 6); - sheet_slide(sht_cons[0], 8, 2); + sheet_slide(sht_back, 0, 0); + sheet_slide(sht_cons[0], 32, 4); sheet_slide(sht_mouse, mx, my); - sheet_updown(sht_back, 0); - sheet_updown(sht_cons[1], 1); - sheet_updown(sht_cons[0], 2); - sheet_updown(sht_mouse, 3); + sheet_updown(sht_back, 0); + sheet_updown(sht_cons[0], 1); + sheet_updown(sht_mouse, 2); key_win = sht_cons[0]; keywin_on(key_win); @@ -216,6 +194,15 @@ void HariMain(void) io_sti(); } } + if (i == 256 + 0x3c && key_shift != 0 && sht_cons[1] == 0) { /* Shift+F2 */ + sht_cons[1] = open_console(shtctl, memtotal); + sheet_slide(sht_cons[1], 32, 4); + sheet_updown(sht_cons[1], shtctl->top); + /*自动将输入焦点切换到新打开的命令行窗口(这样比较方便吧?) */ + keywin_off(key_win); + key_win = sht_cons[1]; + keywin_on(key_win); + } if (i == 256 + 0x57) { /* F11 */ sheet_updown(shtctl->sheets[1], shtctl->top - 1); } @@ -321,3 +308,30 @@ void keywin_on(struct SHEET *key_win) } return; } + +struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct SHEET *sht = sheet_alloc(shtctl); + unsigned char *buf = (unsigned char *) memman_alloc_4k(memman, 256 * 165); + struct TASK *task = task_alloc(); + int *cons_fifo = (int *) memman_alloc_4k(memman, 128 * 4); + sheet_setbuf(sht, buf, 256, 165, -1); /*无透明色*/ + make_window8(buf, 256, 165, "console", 0); + make_textbox8(sht, 8, 28, 240, 128, COL8_000000); + task->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 12; + task->tss.eip = (int) &console_task; + task->tss.es = 1 * 8; + task->tss.cs = 2 * 8; + task->tss.ss = 1 * 8; + task->tss.ds = 1 * 8; + task->tss.fs = 1 * 8; + task->tss.gs = 1 * 8; + *((int *) (task->tss.esp + 4)) = (int) sht; + *((int *) (task->tss.esp + 8)) = memtotal; + task_run(task, 2, 2); /* level=2, priority=2 */ + sht->task = task; + sht->flags |= 0x20; /*有光标*/ + fifo32_init(&task->fifo, 128, cons_fifo, task); + return sht; +} From 6b7a4a13b058f1fe9eb9b623b45d0c8c8b0859d6 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Mon, 16 May 2016 11:46:33 +0800 Subject: [PATCH 31/83] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9B=B4=E5=A4=9A?= =?UTF-8?q?=E7=9A=84=E5=91=BD=E4=BB=A4=E8=A1=8C=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 26_day/bootpack.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/26_day/bootpack.c b/26_day/bootpack.c index abada65..3ec1287 100644 --- a/26_day/bootpack.c +++ b/26_day/bootpack.c @@ -21,7 +21,7 @@ void HariMain(void) struct MOUSE_DEC mdec; struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; unsigned char *buf_back, buf_mouse[256], *buf_cons[2]; - struct SHEET *sht_back, *sht_mouse, *sht_cons[2]; + struct SHEET *sht_back, *sht_mouse; struct TASK *task_a, *task_cons[2], *task; static char keytable0[0x80] = { 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0x08, 0, @@ -77,8 +77,7 @@ void HariMain(void) init_screen8(buf_back, binfo->scrnx, binfo->scrny); /* sht_cons */ - sht_cons[0] = open_console(shtctl, memtotal); - sht_cons[1] = 0; + key_win = open_console(shtctl, memtotal); /* sht_mouse */ sht_mouse = sheet_alloc(shtctl); @@ -88,12 +87,11 @@ void HariMain(void) my = (binfo->scrny - 28 - 16) / 2; sheet_slide(sht_back, 0, 0); - sheet_slide(sht_cons[0], 32, 4); + sheet_slide(key_win, 32, 4); sheet_slide(sht_mouse, mx, my); sheet_updown(sht_back, 0); - sheet_updown(sht_cons[0], 1); + sheet_updown(key_win, 1); sheet_updown(sht_mouse, 2); - key_win = sht_cons[0]; keywin_on(key_win); /*为了避免和键盘当前状态冲突,在一开始先进行设置*/ @@ -194,13 +192,11 @@ void HariMain(void) io_sti(); } } - if (i == 256 + 0x3c && key_shift != 0 && sht_cons[1] == 0) { /* Shift+F2 */ - sht_cons[1] = open_console(shtctl, memtotal); - sheet_slide(sht_cons[1], 32, 4); - sheet_updown(sht_cons[1], shtctl->top); - /*自动将输入焦点切换到新打开的命令行窗口(这样比较方便吧?) */ + if (i == 256 + 0x3c && key_shift != 0 ) { /* Shift+F2 */ keywin_off(key_win); - key_win = sht_cons[1]; + key_win = open_console(shtctl, memtotal); + sheet_slide(key_win, 32, 4); + sheet_updown(key_win, shtctl->top); keywin_on(key_win); } if (i == 256 + 0x57) { /* F11 */ From 884ddf242ec8a554d0be5d643b978e0d32e652b6 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Mon, 16 May 2016 11:59:43 +0800 Subject: [PATCH 32/83] =?UTF-8?q?=E5=85=B3=E9=97=AD=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E8=A1=8C=E7=AA=97=E5=8F=A3=EF=BC=881=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 26_day/bootpack.c | 49 +++++++++++++++++++++++++++++++++++++++-------- 26_day/bootpack.h | 3 ++- 26_day/console.c | 18 +++++++++++++++++ 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/26_day/bootpack.c b/26_day/bootpack.c index 3ec1287..8d16a9e 100644 --- a/26_day/bootpack.c +++ b/26_day/bootpack.c @@ -8,6 +8,8 @@ void keywin_off(struct SHEET *key_win); void keywin_on(struct SHEET *key_win); struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal); +void close_console(struct SHEET *sht); +void close_constask(struct TASK *task); void HariMain(void) { @@ -51,6 +53,7 @@ void HariMain(void) init_pic(); io_sti(); /* IDT/PIC的初始化已经完成,于是开放CPU的中断 */ fifo32_init(&fifo, 128, fifobuf, 0); + *((int *) 0x0fec) = (int) &fifo; init_pit(); init_keyboard(&fifo, 256); enable_mouse(&fifo, 512, &mdec); @@ -123,9 +126,13 @@ void HariMain(void) } else { i = fifo32_get(&fifo); io_sti(); - if (key_win->flags == 0) { /*输入窗口被关闭*/ - key_win = shtctl->sheets[shtctl->top - 1]; - keywin_on(key_win); + if (key_win != 0 && key_win->flags == 0) { /*窗口被关闭*/ + if (shtctl->top == 1) { /*当画面上只剩鼠标和背景时*/ + key_win = 0; + } else { + key_win = shtctl->sheets[shtctl->top - 1]; + keywin_on(key_win); + } } if (256 <= i && i <= 511) { /* 键盘数据*/ if (i < 0x80 + 256) { /*将按键编码转换为字符编码*/ @@ -143,10 +150,10 @@ void HariMain(void) s[0] += 0x20; /*将大写字母转换为小写字母*/ } } - if (s[0] != 0) { /*一般字符、退格键、回车键*/ + if (s[0] != 0 && key_win != 0) { /*一般字符、退格键、回车键*/ fifo32_put(&key_win->task->fifo, s[0] + 256); } - if (i == 256 + 0x0f) { /* Tab键 */ + if (i == 256 + 0x0f && key_win != 0) { /* Tab键 */ keywin_off(key_win); j = key_win->height - 1; if (j == 0) { @@ -182,7 +189,7 @@ void HariMain(void) fifo32_put(&keycmd, KEYCMD_LED); fifo32_put(&keycmd, key_leds); } - if (i == 256 + 0x3b && key_shift != 0) { + if (i == 256 + 0x3b && key_shift != 0 && key_win != 0) { task = key_win->task; if (task != 0 && task->tss.ss0 != 0) { /* Shift+F1 */ cons_putstr0(task->cons, "\nBreak(key) :\n"); @@ -192,8 +199,10 @@ void HariMain(void) io_sti(); } } - if (i == 256 + 0x3c && key_shift != 0 ) { /* Shift+F2 */ - keywin_off(key_win); + if (i == 256 + 0x3c && key_shift != 0) { /* Shift+F2 */ + if (key_win != 0) { + keywin_off(key_win); + } key_win = open_console(shtctl, memtotal); sheet_slide(key_win, 32, 4); sheet_updown(key_win, shtctl->top); @@ -282,6 +291,8 @@ void HariMain(void) } } } + } else if (768 <= i && i <= 1023) { /*命令行窗口关闭处理*/ + close_console(shtctl->sheets0 + (i - 768)); } } } @@ -311,6 +322,8 @@ struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal) struct SHEET *sht = sheet_alloc(shtctl); unsigned char *buf = (unsigned char *) memman_alloc_4k(memman, 256 * 165); struct TASK *task = task_alloc(); + task->cons_stack = memman_alloc_4k(memman, 64 * 1024); + task->tss.esp = task->cons_stack + 64 * 1024 - 12; int *cons_fifo = (int *) memman_alloc_4k(memman, 128 * 4); sheet_setbuf(sht, buf, 256, 165, -1); /*无透明色*/ make_window8(buf, 256, 165, "console", 0); @@ -331,3 +344,23 @@ struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal) fifo32_init(&task->fifo, 128, cons_fifo, task); return sht; } + +void close_constask(struct TASK *task) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + task_sleep(task); + memman_free_4k(memman, task->cons_stack, 64 * 1024); + memman_free_4k(memman, (int) task->fifo.buf, 128 * 4); + task->flags = 0; /*用来替代task_free(task); */ + return; +} + +void close_console(struct SHEET *sht) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = sht->task; + memman_free_4k(memman, (int) sht->buf, 256 * 165); + sheet_free(sht); + close_constask(task); + return; +} diff --git a/26_day/bootpack.h b/26_day/bootpack.h index 9975f09..31a6385 100644 --- a/26_day/bootpack.h +++ b/26_day/bootpack.h @@ -211,7 +211,7 @@ struct TASK { struct FIFO32 fifo; struct TSS32 tss; struct CONSOLE *cons; - int ds_base; + int ds_base, cons_stack; }; struct TASKLEVEL { int running; /*正在运行的任务数量*/ @@ -255,6 +255,7 @@ void cmd_mem(struct CONSOLE *cons, int memtotal); void cmd_cls(struct CONSOLE *cons); void cmd_dir(struct CONSOLE *cons); void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline); +void cmd_exit(struct CONSOLE *cons, int *fat); int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline); int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax); int *inthandler0d(int *esp); diff --git a/26_day/console.c b/26_day/console.c index 1b39bc1..d219b85 100644 --- a/26_day/console.c +++ b/26_day/console.c @@ -173,6 +173,8 @@ void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) cmd_dir(cons); } else if (strncmp(cmdline, "type ", 5) == 0) { cmd_type(cons, fat, cmdline); + } else if (strcmp(cmdline, "exit") == 0) { + cmd_exit(cons, fat); } else if (cmdline[0] != 0) { if (cmd_app(cons, fat, cmdline) == 0) { /*不是命令,不是应用程序,也不是空行*/ @@ -250,6 +252,22 @@ void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline) return; } +void cmd_exit(struct CONSOLE *cons, int *fat) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = task_now(); + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct FIFO32 *fifo = (struct FIFO32 *) *((int *) 0x0fec); + timer_cancel(cons->timer); + memman_free_4k(memman, (int) fat, 4 * 2880); + io_cli(); + fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); /* 768〜1023 */ + io_sti(); + for (;;) { + task_sleep(task); + } +} + int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) { struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; From 0c2b6c5934e067bc3d83396b8506df795d48dba8 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Mon, 16 May 2016 12:36:44 +0800 Subject: [PATCH 33/83] =?UTF-8?q?=E5=85=B3=E9=97=AD=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E8=A1=8C=E7=AA=97=E5=8F=A3=EF=BC=882=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 26_day/bootpack.c | 7 ++++++- 26_day/console.c | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/26_day/bootpack.c b/26_day/bootpack.c index 8d16a9e..a2a4c98 100644 --- a/26_day/bootpack.c +++ b/26_day/bootpack.c @@ -268,8 +268,13 @@ void HariMain(void) task->tss.eax = (int) &(task->tss.esp0); task->tss.eip = (int) asm_end_app; io_sti(); + } else { /*命令行窗口*/ + task = sht->task; + io_cli(); + fifo32_put(&task->fifo, 4); + io_sti(); } - } + } break; } } diff --git a/26_day/console.c b/26_day/console.c index d219b85..2da67d9 100644 --- a/26_day/console.c +++ b/26_day/console.c @@ -54,6 +54,9 @@ void console_task(struct SHEET *sheet, int memtotal) boxfill8(sheet->buf, sheet->bxsize, COL8_000000, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); cons.cur_c = -1; } + if (i == 4) { /*点击命令行窗口的“×”按钮*/ + cmd_exit(&cons, fat); + } if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/ if (i == 8 + 256) { /*退格键*/ From 87b1d4027cde8460dbad12d818d363b1a3d84595 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Mon, 16 May 2016 12:39:56 +0800 Subject: [PATCH 34/83] =?UTF-8?q?start=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 26_day/bootpack.h | 1 + 26_day/console.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/26_day/bootpack.h b/26_day/bootpack.h index 31a6385..5da0cb7 100644 --- a/26_day/bootpack.h +++ b/26_day/bootpack.h @@ -256,6 +256,7 @@ void cmd_cls(struct CONSOLE *cons); void cmd_dir(struct CONSOLE *cons); void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline); void cmd_exit(struct CONSOLE *cons, int *fat); +void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal); int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline); int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax); int *inthandler0d(int *esp); diff --git a/26_day/console.c b/26_day/console.c index 2da67d9..f72e450 100644 --- a/26_day/console.c +++ b/26_day/console.c @@ -178,6 +178,8 @@ void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) cmd_type(cons, fat, cmdline); } else if (strcmp(cmdline, "exit") == 0) { cmd_exit(cons, fat); + } else if (strncmp(cmdline, "start ", 6) == 0) { + cmd_start(cons, cmdline, memtotal); } else if (cmdline[0] != 0) { if (cmd_app(cons, fat, cmdline) == 0) { /*不是命令,不是应用程序,也不是空行*/ @@ -271,6 +273,23 @@ void cmd_exit(struct CONSOLE *cons, int *fat) } } +void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal) +{ + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct SHEET *sht = open_console(shtctl, memtotal); + struct FIFO32 *fifo = &sht->task->fifo; + int i; + sheet_slide(sht, 32, 4); + sheet_updown(sht, shtctl->top); + /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ + for (i = 6; cmdline[i] != 0; i++) { + fifo32_put(fifo, cmdline[i] + 256); + } + fifo32_put(fifo, 10 + 256); /*回车键*/ + cons_newline(cons); + return; +} + int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) { struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; From 02e307eae1bd508babdbb653ce975566bbb29755 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Mon, 16 May 2016 13:10:25 +0800 Subject: [PATCH 35/83] =?UTF-8?q?ncst=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 26_day/bootpack.c | 56 +++++++++++++++++-------------- 26_day/bootpack.h | 5 +++ 26_day/console.c | 84 +++++++++++++++++++++++++++++++++-------------- 3 files changed, 96 insertions(+), 49 deletions(-) diff --git a/26_day/bootpack.c b/26_day/bootpack.c index a2a4c98..46f1742 100644 --- a/26_day/bootpack.c +++ b/26_day/bootpack.c @@ -7,7 +7,6 @@ void keywin_off(struct SHEET *key_win); void keywin_on(struct SHEET *key_win); -struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal); void close_console(struct SHEET *sht); void close_constask(struct TASK *task); @@ -17,14 +16,14 @@ void HariMain(void) struct SHTCTL *shtctl; char s[40]; struct FIFO32 fifo, keycmd; - int fifobuf[128], keycmd_buf[32], *cons_fifo[2]; + int fifobuf[128], keycmd_buf[32]; int mx, my, i, new_mx = -1, new_my = 0, new_wx = 0x7fffffff, new_wy = 0; unsigned int memtotal; struct MOUSE_DEC mdec; struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; - unsigned char *buf_back, buf_mouse[256], *buf_cons[2]; + unsigned char *buf_back, buf_mouse[256]; struct SHEET *sht_back, *sht_mouse; - struct TASK *task_a, *task_cons[2], *task; + struct TASK *task_a, *task; static char keytable0[0x80] = { 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0x08, 0, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0x0a, 0, 'A', 'S', @@ -89,11 +88,11 @@ void HariMain(void) mx = (binfo->scrnx - 16) / 2; /* 计算坐标使其位于画面中央 */ my = (binfo->scrny - 28 - 16) / 2; - sheet_slide(sht_back, 0, 0); - sheet_slide(key_win, 32, 4); + sheet_slide(sht_back, 0, 0); + sheet_slide(key_win, 32, 4); sheet_slide(sht_mouse, mx, my); - sheet_updown(sht_back, 0); - sheet_updown(key_win, 1); + sheet_updown(sht_back, 0); + sheet_updown(key_win, 1); sheet_updown(sht_mouse, 2); keywin_on(key_win); @@ -189,9 +188,9 @@ void HariMain(void) fifo32_put(&keycmd, KEYCMD_LED); fifo32_put(&keycmd, key_leds); } - if (i == 256 + 0x3b && key_shift != 0 && key_win != 0) { + if (i == 256 + 0x3b && key_shift != 0 && key_win != 0) { /* Shift+F1 */ task = key_win->task; - if (task != 0 && task->tss.ss0 != 0) { /* Shift+F1 */ + if (task != 0 && task->tss.ss0 != 0) { cons_putstr0(task->cons, "\nBreak(key) :\n"); io_cli(); /*强制结束处理时禁止任务切换*/ task->tss.eax = (int) &(task->tss.esp0); @@ -199,7 +198,7 @@ void HariMain(void) io_sti(); } } - if (i == 256 + 0x3c && key_shift != 0) { /* Shift+F2 */ + if (i == 256 + 0x3c && key_shift != 0) { /* Shift+F2 */ if (key_win != 0) { keywin_off(key_win); } @@ -256,7 +255,7 @@ void HariMain(void) if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) { mmx = mx; /*进入窗口移动模式*/ mmy = my; - mmx2 = sht->vx0; + mmx2 = sht->vx0; new_wy = sht->vy0; } if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <= y && y < 19) { @@ -274,7 +273,7 @@ void HariMain(void) fifo32_put(&task->fifo, 4); io_sti(); } - } + } break; } } @@ -284,7 +283,7 @@ void HariMain(void) x = mx - mmx; /*计算鼠标指针移动量*/ y = my - mmy; new_wx = (mmx2 + x + 2) & ~3; - new_wy = new_wy + y; + new_wy = new_wy + y; mmy = my; } } else { @@ -293,11 +292,13 @@ void HariMain(void) if (new_wx != 0x7fffffff) { sheet_slide(sht, new_wx, new_wy); /*固定图层位置*/ new_wx = 0x7fffffff; - } + } } } } else if (768 <= i && i <= 1023) { /*命令行窗口关闭处理*/ close_console(shtctl->sheets0 + (i - 768)); + } else if (1024 <= i && i <= 2023) { + close_constask(taskctl->tasks0 + (i - 1024)); } } } @@ -321,19 +322,13 @@ void keywin_on(struct SHEET *key_win) return; } -struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal) +struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal) { struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; - struct SHEET *sht = sheet_alloc(shtctl); - unsigned char *buf = (unsigned char *) memman_alloc_4k(memman, 256 * 165); struct TASK *task = task_alloc(); + int *cons_fifo = (int *) memman_alloc_4k(memman, 128 * 4); task->cons_stack = memman_alloc_4k(memman, 64 * 1024); task->tss.esp = task->cons_stack + 64 * 1024 - 12; - int *cons_fifo = (int *) memman_alloc_4k(memman, 128 * 4); - sheet_setbuf(sht, buf, 256, 165, -1); /*无透明色*/ - make_window8(buf, 256, 165, "console", 0); - make_textbox8(sht, 8, 28, 240, 128, COL8_000000); - task->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 12; task->tss.eip = (int) &console_task; task->tss.es = 1 * 8; task->tss.cs = 2 * 8; @@ -344,9 +339,20 @@ struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal) *((int *) (task->tss.esp + 4)) = (int) sht; *((int *) (task->tss.esp + 8)) = memtotal; task_run(task, 2, 2); /* level=2, priority=2 */ - sht->task = task; - sht->flags |= 0x20; /*有光标*/ fifo32_init(&task->fifo, 128, cons_fifo, task); + return task; +} + +struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct SHEET *sht = sheet_alloc(shtctl); + unsigned char *buf = (unsigned char *) memman_alloc_4k(memman, 256 * 165); + sheet_setbuf(sht, buf, 256, 165, -1); /*无透明色*/ + make_window8(buf, 256, 165, "console", 0); + make_textbox8(sht, 8, 28, 240, 128, COL8_000000); + sht->task = open_constask(sht, memtotal); + sht->flags |= 0x20; /*有光标*/ return sht; } diff --git a/26_day/bootpack.h b/26_day/bootpack.h index 5da0cb7..2195e24 100644 --- a/26_day/bootpack.h +++ b/26_day/bootpack.h @@ -224,6 +224,7 @@ struct TASKCTL { struct TASKLEVEL level[MAX_TASKLEVELS]; struct TASK tasks0[MAX_TASKS]; }; +extern struct TASKCTL *taskctl; extern struct TIMER *task_timer; struct TASK *task_now(void); struct TASK *task_init(struct MEMMAN *memman); @@ -257,6 +258,7 @@ void cmd_dir(struct CONSOLE *cons); void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline); void cmd_exit(struct CONSOLE *cons, int *fat); void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal); +void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal); int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline); int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax); int *inthandler0d(int *esp); @@ -274,3 +276,6 @@ void file_readfat(int *fat, unsigned char *img); void file_loadfile(int clustno, int size, char *buf, int *fat, char *img); struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max); +/* bootpack.c */ +struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal); +struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal); diff --git a/26_day/console.c b/26_day/console.c index f72e450..f85ec8c 100644 --- a/26_day/console.c +++ b/26_day/console.c @@ -17,9 +17,11 @@ void console_task(struct SHEET *sheet, int memtotal) cons.cur_c = -1; task->cons = &cons; - cons.timer = timer_alloc(); - timer_init(cons.timer, &task->fifo, 1); - timer_settime(cons.timer, 50); + if (sheet != 0) { + cons.timer = timer_alloc(); + timer_init(cons.timer, &task->fifo, 1); + timer_settime(cons.timer, 50); + } file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); /*显示提示符*/ @@ -72,6 +74,9 @@ void console_task(struct SHEET *sheet, int memtotal) cmdline[cons.cur_x / 8 - 2] = 0; cons_newline(&cons); cons_runcmd(cmdline, &cons, fat, memtotal); /*运行命令*/ + if (sheet == 0) { + cmd_exit(&cons, fat); + } /*显示提示符*/ cons_putchar(&cons, '>', 1); } else { @@ -84,10 +89,12 @@ void console_task(struct SHEET *sheet, int memtotal) } } /*重新显示光标*/ - if (cons.cur_c >= 0) { - boxfill8(sheet->buf, sheet->bxsize, cons.cur_c, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + if (sheet != 0) { + if (cons.cur_c >= 0) { + boxfill8(sheet->buf, sheet->bxsize, cons.cur_c, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + } + sheet_refresh(sheet, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16); } - sheet_refresh(sheet, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16); } } } @@ -99,8 +106,10 @@ void cons_putchar(struct CONSOLE *cons, int chr, char move) s[1] = 0; if (s[0] == 0x09) { /*制表符*/ for (;;) { - putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1); - cons->cur_x += 8; + if (cons->sht != 0) { + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1); + cons->cur_x += 8; + } if (cons->cur_x == 8 + 240) { cons_newline(cons); } @@ -113,7 +122,9 @@ void cons_putchar(struct CONSOLE *cons, int chr, char move) } else if (s[0] == 0x0d) { /*回车*/ /*先不做任何操作*/ } else { /*一般字符*/ - putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1); + if (cons->sht != 0) { + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1); + } if (move != 0) { /* move为0时光标不后移*/ cons->cur_x += 8; @@ -133,17 +144,19 @@ void cons_newline(struct CONSOLE *cons) cons->cur_y += 16; /*到下一行*/ } else { /*滚动*/ - for (y = 28; y < 28 + 112; y++) { - for (x = 8; x < 8 + 240; x++) { - sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize]; + if (sheet != 0) { + for (y = 28; y < 28 + 112; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize]; + } } - } - for (y = 28 + 112; y < 28 + 128; y++) { - for (x = 8; x < 8 + 240; x++) { - sheet->buf[x + y * sheet->bxsize] = COL8_000000; + for (y = 28 + 112; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); } - sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); } cons->cur_x = 8; return; @@ -168,19 +181,21 @@ void cons_putstr1(struct CONSOLE *cons, char *s, int l) void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) { - if (strcmp(cmdline, "mem") == 0) { + if (strcmp(cmdline, "mem") == 0 && cons->sht != 0) { cmd_mem(cons, memtotal); - } else if (strcmp(cmdline, "cls") == 0) { + } else if (strcmp(cmdline, "cls") == 0 && cons->sht != 0) { cmd_cls(cons); - } else if (strcmp(cmdline, "dir") == 0 || strcmp(cmdline, "ls") == 0) { + } else if ((strcmp(cmdline, "dir") == 0 || strcmp(cmdline, "ls") == 0) && cons->sht != 0) { cmd_dir(cons); - } else if (strncmp(cmdline, "type ", 5) == 0) { + } else if (strncmp(cmdline, "type ", 5) == 0 && cons->sht != 0) { cmd_type(cons, fat, cmdline); } else if (strcmp(cmdline, "exit") == 0) { cmd_exit(cons, fat); } else if (strncmp(cmdline, "start ", 6) == 0) { cmd_start(cons, cmdline, memtotal); - } else if (cmdline[0] != 0) { + } else if (strncmp(cmdline, "ncst ", 5) == 0) { + cmd_ncst(cons, cmdline, memtotal); + }else if (cmdline[0] != 0) { if (cmd_app(cons, fat, cmdline) == 0) { /*不是命令,不是应用程序,也不是空行*/ cons_putstr0(cons, "Bad command.\n\n"); @@ -263,10 +278,16 @@ void cmd_exit(struct CONSOLE *cons, int *fat) struct TASK *task = task_now(); struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); struct FIFO32 *fifo = (struct FIFO32 *) *((int *) 0x0fec); - timer_cancel(cons->timer); + if (cons->sht != 0) { + timer_cancel(cons->timer); + } memman_free_4k(memman, (int) fat, 4 * 2880); io_cli(); - fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); /* 768〜1023 */ + if (cons->sht != 0) { + fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); /* 768〜1023 */ + } else { + fifo32_put(fifo, task - taskctl->tasks0 + 1024); /*1024~2023*/ + } io_sti(); for (;;) { task_sleep(task); @@ -290,6 +311,21 @@ void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal) return; } +void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal) +{ + struct TASK *task = open_constask(0, memtotal); + struct FIFO32 *fifo = &task->fifo; + int i; + + /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ + for (i = 5; cmdline[i] != 0; i++) { + fifo32_put(fifo, cmdline[i] + 256); + } + fifo32_put(fifo, 10 + 256); /*回车键*/ + cons_newline(cons); + return; +} + int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) { struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; From 8785b4602186fa8f3d51bbb51c3c4b499f9bd11f Mon Sep 17 00:00:00 2001 From: Yourtion Date: Tue, 17 May 2016 11:00:38 +0800 Subject: [PATCH 36/83] Add 27 day code --- 27_day/!cons_9x.bat | 1 + 27_day/!cons_nt.bat | 1 + 27_day/Makefile | 232 +++ 27_day/a.c | 8 + 27_day/a_nask.nas | 230 +++ 27_day/asmhead.nas | 202 ++ 27_day/beepdown.c | 24 + 27_day/bootpack.c | 377 ++++ 27_day/bootpack.h | 281 +++ 27_day/color.c | 27 + 27_day/color2.c | 42 + 27_day/console.c | 592 ++++++ 27_day/dsctbl.c | 59 + 27_day/fifo.c | 63 + 27_day/file.c | 74 + 27_day/graphic.c | 167 ++ 27_day/hankaku.txt | 4609 +++++++++++++++++++++++++++++++++++++++++++ 27_day/hello.nas | 16 + 27_day/hello2.nas | 9 + 27_day/hello3.c | 12 + 27_day/hello4.c | 8 + 27_day/hello5.nas | 20 + 27_day/int.c | 26 + 27_day/ipl10.nas | 109 + 27_day/keyboard.c | 44 + 27_day/lines.c | 29 + 27_day/make.bat | 1 + 27_day/memory.c | 162 ++ 27_day/mouse.c | 76 + 27_day/mtask.c | 202 ++ 27_day/naskfunc.nas | 291 +++ 27_day/noodle.c | 42 + 27_day/sheet.c | 294 +++ 27_day/star1.c | 18 + 27_day/stars.c | 24 + 27_day/stars2.c | 26 + 27_day/timer.c | 169 ++ 27_day/walk.c | 35 + 27_day/window.c | 118 ++ 27_day/winhelo.c | 11 + 27_day/winhelo2.c | 15 + 27_day/winhelo3.c | 19 + 42 files changed, 8765 insertions(+) create mode 100644 27_day/!cons_9x.bat create mode 100644 27_day/!cons_nt.bat create mode 100644 27_day/Makefile create mode 100644 27_day/a.c create mode 100644 27_day/a_nask.nas create mode 100644 27_day/asmhead.nas create mode 100644 27_day/beepdown.c create mode 100644 27_day/bootpack.c create mode 100644 27_day/bootpack.h create mode 100644 27_day/color.c create mode 100644 27_day/color2.c create mode 100644 27_day/console.c create mode 100644 27_day/dsctbl.c create mode 100644 27_day/fifo.c create mode 100644 27_day/file.c create mode 100644 27_day/graphic.c create mode 100644 27_day/hankaku.txt create mode 100644 27_day/hello.nas create mode 100644 27_day/hello2.nas create mode 100644 27_day/hello3.c create mode 100644 27_day/hello4.c create mode 100644 27_day/hello5.nas create mode 100644 27_day/int.c create mode 100644 27_day/ipl10.nas create mode 100644 27_day/keyboard.c create mode 100644 27_day/lines.c create mode 100644 27_day/make.bat create mode 100644 27_day/memory.c create mode 100644 27_day/mouse.c create mode 100644 27_day/mtask.c create mode 100644 27_day/naskfunc.nas create mode 100644 27_day/noodle.c create mode 100644 27_day/sheet.c create mode 100644 27_day/star1.c create mode 100644 27_day/stars.c create mode 100644 27_day/stars2.c create mode 100644 27_day/timer.c create mode 100644 27_day/walk.c create mode 100644 27_day/window.c create mode 100644 27_day/winhelo.c create mode 100644 27_day/winhelo2.c create mode 100644 27_day/winhelo3.c diff --git a/27_day/!cons_9x.bat b/27_day/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/27_day/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/27_day/!cons_nt.bat b/27_day/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/27_day/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/27_day/Makefile b/27_day/Makefile new file mode 100644 index 0000000..8714cad --- /dev/null +++ b/27_day/Makefile @@ -0,0 +1,232 @@ +OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \ + int.obj fifo.obj keyboard.obj mouse.obj memory.obj sheet.obj timer.obj \ + mtask.obj window.obj console.obj file.obj + +TOOLPATH = ../z_tools/ +INCPATH = ../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = $(TOOLPATH)haribote/haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +COPY = copy +DEL = del + +# 默认动作 + +default : + $(MAKE) img + +# 镜像文件生成 + +ipl10.bin : ipl10.nas Makefile + $(NASK) ipl10.nas ipl10.bin ipl10.lst + +asmhead.bin : asmhead.nas Makefile + $(NASK) asmhead.nas asmhead.bin asmhead.lst + +hankaku.bin : hankaku.txt Makefile + $(MAKEFONT) hankaku.txt hankaku.bin + +hankaku.obj : hankaku.bin Makefile + $(BIN2OBJ) hankaku.bin hankaku.obj _hankaku + +bootpack.bim : $(OBJS_BOOTPACK) Makefile + $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \ + $(OBJS_BOOTPACK) +# 3MB+64KB=3136KB + +bootpack.hrb : bootpack.bim Makefile + $(BIM2HRB) bootpack.bim bootpack.hrb 0 + +haribote.sys : asmhead.bin bootpack.hrb Makefile + copy /B asmhead.bin+bootpack.hrb haribote.sys + +hello.hrb : hello.nas Makefile + $(NASK) hello.nas hello.hrb hello.lst + +hello2.hrb : hello2.nas Makefile + $(NASK) hello2.nas hello2.hrb hello2.lst + +a.bim : a.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:a.bim map:a.map a.obj a_nask.obj + +a.hrb : a.bim Makefile + $(BIM2HRB) a.bim a.hrb 0 + +hello3.bim : hello3.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello3.bim map:hello3.map hello3.obj a_nask.obj + +hello3.hrb : hello3.bim Makefile + $(BIM2HRB) hello3.bim hello3.hrb 0 + +hello4.bim : hello4.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello4.bim stack:1k map:hello4.map \ + hello4.obj a_nask.obj + +hello4.hrb : hello4.bim Makefile + $(BIM2HRB) hello4.bim hello4.hrb 0 + +hello5.bim : hello5.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello5.bim stack:1k map:hello5.map hello5.obj + +hello5.hrb : hello5.bim Makefile + $(BIM2HRB) hello5.bim hello5.hrb 0 + +winhelo.bim : winhelo.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:winhelo.bim stack:1k map:winhelo.map \ + winhelo.obj a_nask.obj + +winhelo.hrb : winhelo.bim Makefile + $(BIM2HRB) winhelo.bim winhelo.hrb 0 + +winhelo2.bim : winhelo2.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:winhelo2.bim stack:1k map:winhelo2.map \ + winhelo2.obj a_nask.obj + +winhelo2.hrb : winhelo2.bim Makefile + $(BIM2HRB) winhelo2.bim winhelo2.hrb 0 + +winhelo3.bim : winhelo3.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:winhelo3.bim stack:1k map:winhelo3.map \ + winhelo3.obj a_nask.obj + +winhelo3.hrb : winhelo3.bim Makefile + $(BIM2HRB) winhelo3.bim winhelo3.hrb 40k + +star1.bim : star1.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:star1.bim stack:1k map:star1.map \ + star1.obj a_nask.obj + +star1.hrb : star1.bim Makefile + $(BIM2HRB) star1.bim star1.hrb 47k + +stars.bim : stars.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:stars.bim stack:1k map:stars.map \ + stars.obj a_nask.obj + +stars.hrb : stars.bim Makefile + $(BIM2HRB) stars.bim stars.hrb 47k + +stars2.bim : stars2.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:stars2.bim stack:1k map:stars2.map \ + stars2.obj a_nask.obj + +stars2.hrb : stars2.bim Makefile + $(BIM2HRB) stars2.bim stars2.hrb 47k + +lines.bim : lines.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:lines.bim stack:1k map:lines.map \ + lines.obj a_nask.obj + +lines.hrb : lines.bim Makefile + $(BIM2HRB) lines.bim lines.hrb 48k + +walk.bim : walk.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:walk.bim stack:1k map:walk.map \ + walk.obj a_nask.obj + +walk.hrb : walk.bim Makefile + $(BIM2HRB) walk.bim walk.hrb 48k + +noodle.bim : noodle.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:noodle.bim stack:1k map:noodle.map \ + noodle.obj a_nask.obj + +noodle.hrb : noodle.bim Makefile + $(BIM2HRB) noodle.bim noodle.hrb 40k + +beepdown.bim : beepdown.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:beepdown.bim stack:1k map:beepdown.map \ + beepdown.obj a_nask.obj + +beepdown.hrb : beepdown.bim Makefile + $(BIM2HRB) beepdown.bim beepdown.hrb 40k + +color.bim : color.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:color.bim stack:1k map:color.map \ + color.obj a_nask.obj + +color.hrb : color.bim Makefile + $(BIM2HRB) color.bim color.hrb 56k + +color2.bim : color2.obj a_nask.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:color2.bim stack:1k map:color2.map \ + color2.obj a_nask.obj + +color2.hrb : color2.bim Makefile + $(BIM2HRB) color2.bim color2.hrb 56k + +haribote.img : ipl10.bin haribote.sys Makefile \ + hello.hrb hello2.hrb a.hrb hello3.hrb hello4.hrb hello5.hrb \ + winhelo.hrb winhelo2.hrb winhelo3.hrb star1.hrb stars.hrb stars2.hrb \ + lines.hrb walk.hrb noodle.hrb beepdown.hrb color.hrb color2.hrb + $(EDIMG) imgin:../z_tools/fdimg0at.tek \ + wbinimg src:ipl10.bin len:512 from:0 to:0 \ + copy from:haribote.sys to:@: \ + copy from:ipl10.nas to:@: \ + copy from:make.bat to:@: \ + copy from:hello.hrb to:@: \ + copy from:hello2.hrb to:@: \ + copy from:a.hrb to:@: \ + copy from:hello3.hrb to:@: \ + copy from:hello4.hrb to:@: \ + copy from:hello5.hrb to:@: \ + copy from:winhelo.hrb to:@: \ + copy from:winhelo2.hrb to:@: \ + copy from:winhelo3.hrb to:@: \ + copy from:star1.hrb to:@: \ + copy from:stars.hrb to:@: \ + copy from:stars2.hrb to:@: \ + copy from:lines.hrb to:@: \ + copy from:walk.hrb to:@: \ + copy from:noodle.hrb to:@: \ + copy from:beepdown.hrb to:@: \ + copy from:color.hrb to:@: \ + copy from:color2.hrb to:@: \ + imgout:haribote.img + +# 其他指令 + +%.gas : %.c bootpack.h Makefile + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +# 运行程序 + +img : + $(MAKE) haribote.img + +run : + $(MAKE) img + $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../z_tools/qemu + +install : + $(MAKE) img + $(IMGTOL) w a: haribote.img + +clean : + -$(DEL) *.bin + -$(DEL) *.lst + -$(DEL) *.obj + -$(DEL) bootpack.map + -$(DEL) bootpack.bim + -$(DEL) bootpack.hrb + -$(DEL) haribote.sys + +src_only : + $(MAKE) clean + -$(DEL) haribote.img diff --git a/27_day/a.c b/27_day/a.c new file mode 100644 index 0000000..a6668af --- /dev/null +++ b/27_day/a.c @@ -0,0 +1,8 @@ +void api_putchar(int c); +void api_end(void); + +void HariMain(void) +{ + api_putchar('A'); + api_end(); +} diff --git a/27_day/a_nask.nas b/27_day/a_nask.nas new file mode 100644 index 0000000..9e63654 --- /dev/null +++ b/27_day/a_nask.nas @@ -0,0 +1,230 @@ +[FORMAT "WCOFF"] ; 生成对象文件的模式 +[INSTRSET "i486p"] ; 表示使用486兼容指令集 +[BITS 32] ; 生成32位模式机器语言 +[FILE "a_nask.nas"] ; 源文件名信息 + + GLOBAL _api_putchar + GLOBAL _api_putstr0 + GLOBAL _api_end + GLOBAL _api_openwin + GLOBAL _api_putstrwin + GLOBAL _api_boxfilwin + GLOBAL _api_initmalloc + GLOBAL _api_malloc + GLOBAL _api_free + GLOBAL _api_point + GLOBAL _api_refreshwin + GLOBAL _api_linewin + GLOBAL _api_closewin + GLOBAL _api_getkey + GLOBAL _api_alloctimer + GLOBAL _api_inittimer + GLOBAL _api_settimer + GLOBAL _api_freetimer + GLOBAL _api_beep + +[SECTION .text] + +_api_putchar: ; void api_putchar(int c); + MOV EDX,1 + MOV AL,[ESP+4] ; c + INT 0x40 + RET + +_api_putstr0: ; void api_putstr0(char *s); + PUSH EBX + MOV EDX,2 + MOV EBX,[ESP+8] ; s + INT 0x40 + POP EBX + RET + +_api_end: ; void api_end(void); + MOV EDX,4 + INT 0x40 + +_api_openwin: ; int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,5 + MOV EBX,[ESP+16] ; buf + MOV ESI,[ESP+20] ; xsiz + MOV EDI,[ESP+24] ; ysiz + MOV EAX,[ESP+28] ; col_inv + MOV ECX,[ESP+32] ; title + INT 0x40 + POP EBX + POP ESI + POP EDI + RET + +_api_putstrwin: ; void api_putstrwin(int win, int x, int y, int col, int len, char *str); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,6 + MOV EBX,[ESP+20] ; win + MOV ESI,[ESP+24] ; x + MOV EDI,[ESP+28] ; y + MOV EAX,[ESP+32] ; col + MOV ECX,[ESP+36] ; len + MOV EBP,[ESP+40] ; str + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET + +_api_boxfilwin: ; void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,7 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET + +_api_initmalloc: ; void api_initmalloc(void); + PUSH EBX + MOV EDX,8 + MOV EBX,[CS:0x0020] ; malloc内存空间的地址 + MOV EAX,EBX + ADD EAX,32*1024 ; 加上32KB + MOV ECX,[CS:0x0000] ; 数据段的大小 + SUB ECX,EAX + INT 0x40 + POP EBX + RET + +_api_malloc: ; char *api_malloc(int size); + PUSH EBX + MOV EDX,9 + MOV EBX,[CS:0x0020] + MOV ECX,[ESP+8] ; size + INT 0x40 + POP EBX + RET + +_api_free: ; void api_free(char *addr, int size); + PUSH EBX + MOV EDX,10 + MOV EBX,[CS:0x0020] + MOV EAX,[ESP+ 8] ; addr + MOV ECX,[ESP+12] ; size + INT 0x40 + POP EBX + RET + +_api_point: ; void api_point(int win, int x, int y, int col); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,11 + MOV EBX,[ESP+16] ; win + MOV ESI,[ESP+20] ; x + MOV EDI,[ESP+24] ; y + MOV EAX,[ESP+28] ; col + INT 0x40 + POP EBX + POP ESI + POP EDI + RET + +_api_refreshwin: ; void api_refreshwin(int win, int x0, int y0, int x1, int y1); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,12 + MOV EBX,[ESP+16] ; win + MOV EAX,[ESP+20] ; x0 + MOV ECX,[ESP+24] ; y0 + MOV ESI,[ESP+28] ; x1 + MOV EDI,[ESP+32] ; y1 + INT 0x40 + POP EBX + POP ESI + POP EDI + RET + +_api_linewin: ; void api_linewin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,13 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET + +_api_closewin: ; void api_closewin(int win); + PUSH EBX + MOV EDX,14 + MOV EBX,[ESP+8] ; win + INT 0x40 + POP EBX + RET + +_api_getkey: ; int api_getkey(int mode); + MOV EDX,15 + MOV EAX,[ESP+4] ; mode + INT 0x40 + RET + +_api_alloctimer: ; int api_alloctimer(void); + MOV EDX,16 + INT 0x40 + RET + +_api_inittimer: ; void api_inittimer(int timer, int data); + PUSH EBX + MOV EDX,17 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; data + INT 0x40 + POP EBX + RET + +_api_settimer: ; void api_settimer(int timer, int time); + PUSH EBX + MOV EDX,18 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; time + INT 0x40 + POP EBX + RET + +_api_freetimer: ; void api_freetimer(int timer); + PUSH EBX + MOV EDX,19 + MOV EBX,[ESP+ 8] ; timer + INT 0x40 + POP EBX + RET + +_api_beep: ; void api_beep(int tone); + MOV EDX,20 + MOV EAX,[ESP+4] ; tone + INT 0x40 + RET diff --git a/27_day/asmhead.nas b/27_day/asmhead.nas new file mode 100644 index 0000000..ad35d76 --- /dev/null +++ b/27_day/asmhead.nas @@ -0,0 +1,202 @@ +; haribote-os boot asm +; TAB=4 + +[INSTRSET "i486p"] + +VBEMODE EQU 0x105 ; 1024 x 768 x 8bit 彩色 +; 显示模式 +; 0x100 : 640 x 400 x 8bit 彩色 +; 0x101 : 640 x 480 x 8bit 彩色 +; 0x103 : 800 x 600 x 8bit 彩色 +; 0x105 : 1024 x 768 x 8bit 彩色 +; 0x107 : 1280 x 1024 x 8bit 彩色 + +BOTPAK EQU 0x00280000 ; 加载bootpack +DSKCAC EQU 0x00100000 ; 磁盘缓存的位置 +DSKCAC0 EQU 0x00008000 ; 磁盘缓存的位置(实模式) + +; BOOT_INFO 相关 +CYLS EQU 0x0ff0 ; 引导扇区设置 +LEDS EQU 0x0ff1 +VMODE EQU 0x0ff2 ; 关于颜色的信息 +SCRNX EQU 0x0ff4 ; 分辨率X +SCRNY EQU 0x0ff6 ; 分辨率Y +VRAM EQU 0x0ff8 ; 图像缓冲区的起始地址 + + ORG 0xc200 ; 这个的程序要被装载的内存地址 + +; 确认VBE是否存在 + + MOV AX,0x9000 + MOV ES,AX + MOV DI,0 + MOV AX,0x4f00 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 检查VBE的版本 + + MOV AX,[ES:DI+4] + CMP AX,0x0200 + JB scrn320 ; if (AX < 0x0200) goto scrn320 + +; 取得画面模式信息 + + MOV CX,VBEMODE + MOV AX,0x4f01 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 画面模式信息的确认 + CMP BYTE [ES:DI+0x19],8 ;颜色数必须为8 + JNE scrn320 + CMP BYTE [ES:DI+0x1b],4 ;颜色的指定方法必须为4(4是调色板模式) + JNE scrn320 + MOV AX,[ES:DI+0x00] ;模式属性bit7不是1就不能加上0x4000 + AND AX,0x0080 + JZ scrn320 ; 模式属性的bit7是0,所以放弃 + +; 画面设置 + + MOV BX,VBEMODE+0x4000 + MOV AX,0x4f02 + INT 0x10 + MOV BYTE [VMODE],8 ; 屏幕的模式(参考C语言的引用) + MOV AX,[ES:DI+0x12] + MOV [SCRNX],AX + MOV AX,[ES:DI+0x14] + MOV [SCRNY],AX + MOV EAX,[ES:DI+0x28] ;VRAM的地址 + MOV [VRAM],EAX + JMP keystatus + +scrn320: + MOV AL,0x13 ; VGA图、320x200x8bit彩色 + MOV AH,0x00 + INT 0x10 + MOV BYTE [VMODE],8 ; 记下画面模式(参考C语言) + MOV WORD [SCRNX],320 + MOV WORD [SCRNY],200 + MOV DWORD [VRAM],0x000a0000 + +; 通过 BIOS 获取指示灯状态 + +keystatus: + MOV AH,0x02 + INT 0x16 ; keyboard BIOS + MOV [LEDS],AL + +; PIC关闭一切中断 +; 根据AT兼容机的规格,如果要初始化PIC, +; 必须在CLI之前进行,否则有时会挂起。 +; 随后进行PIC的初始化。 + + MOV AL,0xff + OUT 0x21,AL + NOP ; 如果连续执行OUT指令,有些机种会无法正常运行 + OUT 0xa1,AL + + CLI ; 禁止CPU级别的中断 + +; 为了让CPU能够访问1MB以上的内存空间,设定A20GATE + + CALL waitkbdout + MOV AL,0xd1 + OUT 0x64,AL + CALL waitkbdout + MOV AL,0xdf ; enable A20 + OUT 0x60,AL + CALL waitkbdout + +; 切换到保护模式 + +[INSTRSET "i486p"] ; 说明使用486指令 + + LGDT [GDTR0] ; 设置临时GDT + MOV EAX,CR0 + AND EAX,0x7fffffff ; 设bit31为0(禁用分页) + OR EAX,0x00000001 ; bit0到1转换(保护模式过渡) + MOV CR0,EAX + JMP pipelineflush +pipelineflush: + MOV AX,1*8 ; 可读写的段 32bit + MOV DS,AX + MOV ES,AX + MOV FS,AX + MOV GS,AX + MOV SS,AX + +; bootpack传递 + + MOV ESI,bootpack ; 转送源 + MOV EDI,BOTPAK ; 转送目标 + MOV ECX,512*1024/4 + CALL memcpy + +; 磁盘数据最终转送到它本来的位置去 +; 首先从启动扇区开始 + + MOV ESI,0x7c00 ; 转送源 + MOV EDI,DSKCAC ; 转送目标 + MOV ECX,512/4 + CALL memcpy + +; 剩余的全部 + + MOV ESI,DSKCAC0+512 ; 转送源 + MOV EDI,DSKCAC+512 ; 转送源目标 + MOV ECX,0 + MOV CL,BYTE [CYLS] + IMUL ECX,512*18*2/4 ; 从柱面数变换为字节数/4 + SUB ECX,512/4 ; 减去 IPL 偏移量 + CALL memcpy + +; 必须由asmhead来完成的工作,至此全部完毕 +; 以后就交由bootpack来完成 + +; bootpack启动 + + MOV EBX,BOTPAK + MOV ECX,[EBX+16] + ADD ECX,3 ; ECX += 3; + SHR ECX,2 ; ECX /= 4; + JZ skip ; 没有要转送的东西时 + MOV ESI,[EBX+20] ; 转送源 + ADD ESI,EBX + MOV EDI,[EBX+12] ; 转送目标 + CALL memcpy +skip: + MOV ESP,[EBX+12] ; 堆栈的初始化 + JMP DWORD 2*8:0x0000001b + +waitkbdout: + IN AL,0x64 + AND AL,0x02 + JNZ waitkbdout ; AND的结果如果不是0,就跳到waitkbdout + RET + +memcpy: + MOV EAX,[ESI] + ADD ESI,4 + MOV [EDI],EAX + ADD EDI,4 + SUB ECX,1 + JNZ memcpy ; 减法运算的结果如果不是0,就跳转到memcpy + RET +; memcpy地址前缀大小 + + ALIGNB 16 +GDT0: + RESB 8 ; 初始值 + DW 0xffff,0x0000,0x9200,0x00cf ; 可以读写的段(segment)32bit + DW 0xffff,0x0000,0x9a28,0x0047 ; 可执行的文件的32bit寄存器(bootpack用) + + DW 0 +GDTR0: + DW 8*3-1 + DD GDT0 + + ALIGNB 16 +bootpack: diff --git a/27_day/beepdown.c b/27_day/beepdown.c new file mode 100644 index 0000000..db1aa59 --- /dev/null +++ b/27_day/beepdown.c @@ -0,0 +1,24 @@ +void api_end(void); +int api_getkey(int mode); +int api_alloctimer(void); +void api_inittimer(int timer, int data); +void api_settimer(int timer, int time); +void api_beep(int tone); + +void HariMain(void) +{ + int i, timer; + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (i = 20000000; i >= 20000; i -= i / 100) { + /* 20KHz~20Hz,即人类可以听到的声音范围*/ + /* i以1%的速度递减*/ + api_beep(i); + api_settimer(timer, 1); /* 0.01秒*/ + if (api_getkey(1) != 128) { + break; + } + } + api_beep(0); + api_end(); +} diff --git a/27_day/bootpack.c b/27_day/bootpack.c new file mode 100644 index 0000000..46f1742 --- /dev/null +++ b/27_day/bootpack.c @@ -0,0 +1,377 @@ +/* bootpack */ + +#include "bootpack.h" +#include + +#define KEYCMD_LED 0xed + +void keywin_off(struct SHEET *key_win); +void keywin_on(struct SHEET *key_win); +void close_console(struct SHEET *sht); +void close_constask(struct TASK *task); + +void HariMain(void) +{ + struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; + struct SHTCTL *shtctl; + char s[40]; + struct FIFO32 fifo, keycmd; + int fifobuf[128], keycmd_buf[32]; + int mx, my, i, new_mx = -1, new_my = 0, new_wx = 0x7fffffff, new_wy = 0; + unsigned int memtotal; + struct MOUSE_DEC mdec; + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + unsigned char *buf_back, buf_mouse[256]; + struct SHEET *sht_back, *sht_mouse; + struct TASK *task_a, *task; + static char keytable0[0x80] = { + 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0x08, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0x0a, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0 + }; + static char keytable1[0x80] = { + 0, 0, '!', 0x22, '#', '$', '%', '&', 0x27, '(', ')', '~', '=', '~', 0x08, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0x0a, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', '+', '*', 0, 0, '}', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, '|', 0, 0 + }; + int key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; + int j, x, y, mmx = -1, mmy = -1, mmx2 = 0; + struct SHEET *sht = 0, *key_win; + + init_gdtidt(); + init_pic(); + io_sti(); /* IDT/PIC的初始化已经完成,于是开放CPU的中断 */ + fifo32_init(&fifo, 128, fifobuf, 0); + *((int *) 0x0fec) = (int) &fifo; + init_pit(); + init_keyboard(&fifo, 256); + enable_mouse(&fifo, 512, &mdec); + io_out8(PIC0_IMR, 0xf8); /* 设定PIT和PIC1以及键盘为许可(11111000) */ + io_out8(PIC1_IMR, 0xef); /* 开放鼠标中断(11101111) */ + fifo32_init(&keycmd, 32, keycmd_buf, 0); + + memtotal = memtest(0x00400000, 0xbfffffff); + memman_init(memman); + memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */ + memman_free(memman, 0x00400000, memtotal - 0x00400000); + + init_palette(); + shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny); + task_a = task_init(memman); + fifo.task = task_a; + task_run(task_a, 1, 2); + *((int *) 0x0fe4) = (int) shtctl; + + /* sht_back */ + sht_back = sheet_alloc(shtctl); + buf_back = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny); + sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 无透明色 */ + init_screen8(buf_back, binfo->scrnx, binfo->scrny); + + /* sht_cons */ + key_win = open_console(shtctl, memtotal); + + /* sht_mouse */ + sht_mouse = sheet_alloc(shtctl); + sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99); + init_mouse_cursor8(buf_mouse, 99); + mx = (binfo->scrnx - 16) / 2; /* 计算坐标使其位于画面中央 */ + my = (binfo->scrny - 28 - 16) / 2; + + sheet_slide(sht_back, 0, 0); + sheet_slide(key_win, 32, 4); + sheet_slide(sht_mouse, mx, my); + sheet_updown(sht_back, 0); + sheet_updown(key_win, 1); + sheet_updown(sht_mouse, 2); + keywin_on(key_win); + + /*为了避免和键盘当前状态冲突,在一开始先进行设置*/ + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + + for (;;) { + if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0) { + /* 如果存在向键盘控制器发送的数据,则发送它 */ + keycmd_wait = fifo32_get(&keycmd); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + io_cli(); + if (fifo32_status(&fifo) == 0) { + /* FIFO为空,当存在搁置的绘图操作时立即执行*/ + if (new_mx >= 0) { + io_sti(); + sheet_slide(sht_mouse, new_mx, new_my); + new_mx = -1; + } else if (new_wx != 0x7fffffff) { + io_sti(); + sheet_slide(sht, new_wx, new_wy); + new_wx = 0x7fffffff; + } else { + task_sleep(task_a); + io_sti(); + } + } else { + i = fifo32_get(&fifo); + io_sti(); + if (key_win != 0 && key_win->flags == 0) { /*窗口被关闭*/ + if (shtctl->top == 1) { /*当画面上只剩鼠标和背景时*/ + key_win = 0; + } else { + key_win = shtctl->sheets[shtctl->top - 1]; + keywin_on(key_win); + } + } + if (256 <= i && i <= 511) { /* 键盘数据*/ + if (i < 0x80 + 256) { /*将按键编码转换为字符编码*/ + if (key_shift == 0) { + s[0] = keytable0[i - 256]; + } else { + s[0] = keytable1[i - 256]; + } + } else { + s[0] = 0; + } + if ('A' <= s[0] && s[0] <= 'Z') { /*当输入字符为英文字母时*/ + if (((key_leds & 4) == 0 && key_shift == 0) || + ((key_leds & 4) != 0 && key_shift != 0)) { + s[0] += 0x20; /*将大写字母转换为小写字母*/ + } + } + if (s[0] != 0 && key_win != 0) { /*一般字符、退格键、回车键*/ + fifo32_put(&key_win->task->fifo, s[0] + 256); + } + if (i == 256 + 0x0f && key_win != 0) { /* Tab键 */ + keywin_off(key_win); + j = key_win->height - 1; + if (j == 0) { + j = shtctl->top - 1; + } + key_win = shtctl->sheets[j]; + keywin_on(key_win); + } + if (i == 256 + 0x2a) { /*左Shift ON */ + key_shift |= 1; + } + if (i == 256 + 0x36) { /*右Shift ON */ + key_shift |= 2; + } + if (i == 256 + 0xaa) { /*左Shift OFF */ + key_shift &= ~1; + } + if (i == 256 + 0xb6) { /*右Shift OFF */ + key_shift &= ~2; + } + if (i == 256 + 0x3a) { /* CapsLock */ + key_leds ^= 4; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x45) { /* NumLock */ + key_leds ^= 2; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x46) { /* ScrollLock */ + key_leds ^= 1; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x3b && key_shift != 0 && key_win != 0) { /* Shift+F1 */ + task = key_win->task; + if (task != 0 && task->tss.ss0 != 0) { + cons_putstr0(task->cons, "\nBreak(key) :\n"); + io_cli(); /*强制结束处理时禁止任务切换*/ + task->tss.eax = (int) &(task->tss.esp0); + task->tss.eip = (int) asm_end_app; + io_sti(); + } + } + if (i == 256 + 0x3c && key_shift != 0) { /* Shift+F2 */ + if (key_win != 0) { + keywin_off(key_win); + } + key_win = open_console(shtctl, memtotal); + sheet_slide(key_win, 32, 4); + sheet_updown(key_win, shtctl->top); + keywin_on(key_win); + } + if (i == 256 + 0x57) { /* F11 */ + sheet_updown(shtctl->sheets[1], shtctl->top - 1); + } + if (i == 256 + 0xfa) { /*键盘成功接收到数据*/ + keycmd_wait = -1; + } + if (i == 256 + 0xfe) { /*键盘没有成功接收到数据*/ + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + } else if (512 <= i && i <= 767) { /* 鼠标数据*/ + if (mouse_decode(&mdec, i - 512) != 0) { + /* 已经收集了3字节的数据,移动光标 */ + mx += mdec.x; + my += mdec.y; + if (mx < 0) { + mx = 0; + } + if (my < 0) { + my = 0; + } + if (mx > binfo->scrnx - 1) { + mx = binfo->scrnx - 1; + } + if (my > binfo->scrny - 1) { + my = binfo->scrny - 1; + } + new_mx = mx; + new_my = my; + if ((mdec.btn & 0x01) != 0) { /* 按下左键 */ + if (mmx < 0) { + /*如果处于通常模式*/ + /*按照从上到下的顺序寻找鼠标所指向的图层*/ + for (j = shtctl->top - 1; j > 0; j--) { + sht = shtctl->sheets[j]; + x = mx - sht->vx0; + y = my - sht->vy0; + if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) { + if (sht->buf[y * sht->bxsize + x] != sht->col_inv) { + sheet_updown(sht, shtctl->top - 1); + if (sht != key_win) { + keywin_off(key_win); + key_win = sht; + keywin_on(key_win); + } + if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) { + mmx = mx; /*进入窗口移动模式*/ + mmy = my; + mmx2 = sht->vx0; + new_wy = sht->vy0; + } + if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <= y && y < 19) { + /*点击“×”按钮*/ + if ((sht->flags & 0x10) != 0) { /*该窗口是否为应用程序窗口?*/ + task = sht->task; + cons_putstr0(task->cons, "\nBreak(mouse) :\n"); + io_cli(); /*强制结束处理时禁止任务切换*/ + task->tss.eax = (int) &(task->tss.esp0); + task->tss.eip = (int) asm_end_app; + io_sti(); + } else { /*命令行窗口*/ + task = sht->task; + io_cli(); + fifo32_put(&task->fifo, 4); + io_sti(); + } + } + break; + } + } + } + } else { + /*如果处于窗口移动模式*/ + x = mx - mmx; /*计算鼠标指针移动量*/ + y = my - mmy; + new_wx = (mmx2 + x + 2) & ~3; + new_wy = new_wy + y; + mmy = my; + } + } else { + /*没有按下左键*/ + mmx = -1; /*切换到一般模式*/ + if (new_wx != 0x7fffffff) { + sheet_slide(sht, new_wx, new_wy); /*固定图层位置*/ + new_wx = 0x7fffffff; + } + } + } + } else if (768 <= i && i <= 1023) { /*命令行窗口关闭处理*/ + close_console(shtctl->sheets0 + (i - 768)); + } else if (1024 <= i && i <= 2023) { + close_constask(taskctl->tasks0 + (i - 1024)); + } + } + } +} + +void keywin_off(struct SHEET *key_win) +{ + change_wtitle8(key_win, 0); + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 3); /*命令行窗口光标OFF */ + } + return; +} + +void keywin_on(struct SHEET *key_win) +{ + change_wtitle8(key_win, 1); + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 2); /*命令行窗口光标ON */ + } + return; +} + +struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = task_alloc(); + int *cons_fifo = (int *) memman_alloc_4k(memman, 128 * 4); + task->cons_stack = memman_alloc_4k(memman, 64 * 1024); + task->tss.esp = task->cons_stack + 64 * 1024 - 12; + task->tss.eip = (int) &console_task; + task->tss.es = 1 * 8; + task->tss.cs = 2 * 8; + task->tss.ss = 1 * 8; + task->tss.ds = 1 * 8; + task->tss.fs = 1 * 8; + task->tss.gs = 1 * 8; + *((int *) (task->tss.esp + 4)) = (int) sht; + *((int *) (task->tss.esp + 8)) = memtotal; + task_run(task, 2, 2); /* level=2, priority=2 */ + fifo32_init(&task->fifo, 128, cons_fifo, task); + return task; +} + +struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct SHEET *sht = sheet_alloc(shtctl); + unsigned char *buf = (unsigned char *) memman_alloc_4k(memman, 256 * 165); + sheet_setbuf(sht, buf, 256, 165, -1); /*无透明色*/ + make_window8(buf, 256, 165, "console", 0); + make_textbox8(sht, 8, 28, 240, 128, COL8_000000); + sht->task = open_constask(sht, memtotal); + sht->flags |= 0x20; /*有光标*/ + return sht; +} + +void close_constask(struct TASK *task) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + task_sleep(task); + memman_free_4k(memman, task->cons_stack, 64 * 1024); + memman_free_4k(memman, (int) task->fifo.buf, 128 * 4); + task->flags = 0; /*用来替代task_free(task); */ + return; +} + +void close_console(struct SHEET *sht) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = sht->task; + memman_free_4k(memman, (int) sht->buf, 256 * 165); + sheet_free(sht); + close_constask(task); + return; +} diff --git a/27_day/bootpack.h b/27_day/bootpack.h new file mode 100644 index 0000000..2195e24 --- /dev/null +++ b/27_day/bootpack.h @@ -0,0 +1,281 @@ +/* asmhead.nas */ +struct BOOTINFO { /* 0x0ff0-0x0fff */ + char cyls; /* 启动区读磁盘读到此为止 */ + char leds; /* 启动时键盘的LED的状态 */ + char vmode; /* 显卡模式为多少位彩色 */ + char reserve; + short scrnx, scrny; /* 画面分辨率 */ + char *vram; +}; +#define ADR_BOOTINFO 0x00000ff0 +#define ADR_DISKIMG 0x00100000 + +/* naskfunc.nas */ +void io_hlt(void); +void io_cli(void); +void io_sti(void); +void io_stihlt(void); +int io_in8(int port); +void io_out8(int port, int data); +int io_load_eflags(void); +void io_store_eflags(int eflags); +void load_gdtr(int limit, int addr); +void load_idtr(int limit, int addr); +int load_cr0(void); +void store_cr0(int cr0); +void load_tr(int tr); +void asm_inthandler0c(void); +void asm_inthandler0d(void); +void asm_inthandler20(void); +void asm_inthandler21(void); +void asm_inthandler2c(void); +unsigned int memtest_sub(unsigned int start, unsigned int end); +void farjmp(int eip, int cs); +void farcall(int eip, int cs); +void asm_hrb_api(void); +void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); +void asm_end_app(void); + +/* fifo.c */ +struct FIFO32 { + int *buf; + int p, q, size, free, flags; + struct TASK *task; +}; +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task); +int fifo32_put(struct FIFO32 *fifo, int data); +int fifo32_get(struct FIFO32 *fifo); +int fifo32_status(struct FIFO32 *fifo); + +/* graphic.c */ +void init_palette(void); +void set_palette(int start, int end, unsigned char *rgb); +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); +void init_screen8(char *vram, int x, int y); +void putfont8(char *vram, int xsize, int x, int y, char c, char *font); +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s); +void init_mouse_cursor8(char *mouse, char bc); +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize); +#define COL8_000000 0 +#define COL8_FF0000 1 +#define COL8_00FF00 2 +#define COL8_FFFF00 3 +#define COL8_0000FF 4 +#define COL8_FF00FF 5 +#define COL8_00FFFF 6 +#define COL8_FFFFFF 7 +#define COL8_C6C6C6 8 +#define COL8_840000 9 +#define COL8_008400 10 +#define COL8_848400 11 +#define COL8_000084 12 +#define COL8_840084 13 +#define COL8_008484 14 +#define COL8_848484 15 + +/* dsctbl.c */ +struct SEGMENT_DESCRIPTOR { + short limit_low, base_low; + char base_mid, access_right; + char limit_high, base_high; +}; +struct GATE_DESCRIPTOR { + short offset_low, selector; + char dw_count, access_right; + short offset_high; +}; +void init_gdtidt(void); +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar); +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar); +#define ADR_IDT 0x0026f800 +#define LIMIT_IDT 0x000007ff +#define ADR_GDT 0x00270000 +#define LIMIT_GDT 0x0000ffff +#define ADR_BOTPAK 0x00280000 +#define LIMIT_BOTPAK 0x0007ffff +#define AR_DATA32_RW 0x4092 +#define AR_CODE32_ER 0x409a +#define AR_TSS32 0x0089 +#define AR_INTGATE32 0x008e + +/* int.c */ +void init_pic(void); +#define PIC0_ICW1 0x0020 +#define PIC0_OCW2 0x0020 +#define PIC0_IMR 0x0021 +#define PIC0_ICW2 0x0021 +#define PIC0_ICW3 0x0021 +#define PIC0_ICW4 0x0021 +#define PIC1_ICW1 0x00a0 +#define PIC1_OCW2 0x00a0 +#define PIC1_IMR 0x00a1 +#define PIC1_ICW2 0x00a1 +#define PIC1_ICW3 0x00a1 +#define PIC1_ICW4 0x00a1 + +/* keyboard.c */ +void inthandler21(int *esp); +void wait_KBC_sendready(void); +void init_keyboard(struct FIFO32 *fifo, int data0); +#define PORT_KEYDAT 0x0060 +#define PORT_KEYCMD 0x0064 + +/* mouse.c */ +struct MOUSE_DEC { + unsigned char buf[3], phase; + int x, y, btn; +}; +void inthandler2c(int *esp); +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec); +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat); + +/* memory.c */ +#define MEMMAN_FREES 4090 /* ����Ŗ�32KB */ +#define MEMMAN_ADDR 0x003c0000 +struct FREEINFO { /* ������� */ + unsigned int addr, size; +}; +struct MEMMAN { /* �������Ǘ� */ + int frees, maxfrees, lostsize, losts; + struct FREEINFO free[MEMMAN_FREES]; +}; +unsigned int memtest(unsigned int start, unsigned int end); +void memman_init(struct MEMMAN *man); +unsigned int memman_total(struct MEMMAN *man); +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size); +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size); +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size); +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size); + +/* sheet.c */ +#define MAX_SHEETS 256 +struct SHEET { + unsigned char *buf; + int bxsize, bysize, vx0, vy0, col_inv, height, flags; + struct SHTCTL *ctl; + struct TASK *task; +}; +struct SHTCTL { + unsigned char *vram, *map; + int xsize, ysize, top; + struct SHEET *sheets[MAX_SHEETS]; + struct SHEET sheets0[MAX_SHEETS]; +}; +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize); +struct SHEET *sheet_alloc(struct SHTCTL *ctl); +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv); +void sheet_updown(struct SHEET *sht, int height); +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1); +void sheet_slide(struct SHEET *sht, int vx0, int vy0); +void sheet_free(struct SHEET *sht); + +/* timer.c */ +#define MAX_TIMER 500 +struct TIMER { + struct TIMER *next; + unsigned int timeout; + char flags, flags2; + struct FIFO32 *fifo; + int data; +}; +struct TIMERCTL { + unsigned int count, next; + struct TIMER *t0; + struct TIMER timers0[MAX_TIMER]; +}; +extern struct TIMERCTL timerctl; +void init_pit(void); +struct TIMER *timer_alloc(void); +void timer_free(struct TIMER *timer); +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data); +void timer_settime(struct TIMER *timer, unsigned int timeout); +void inthandler20(int *esp); +int timer_cancel(struct TIMER *timer); +void timer_cancelall(struct FIFO32 *fifo); + +/* mtask.c */ +#define MAX_TASKS 1000 /*最大任务数量*/ +#define TASK_GDT0 3 /*定义从GDT的几号开始分配给TSS */ +#define MAX_TASKS_LV 100 +#define MAX_TASKLEVELS 10 +struct TSS32 { + int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3; + int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi; + int es, cs, ss, ds, fs, gs; + int ldtr, iomap; +}; +struct TASK { + int sel, flags; /* sel用来存放GDT的编号*/ + int level, priority; /* 优先级 */ + struct FIFO32 fifo; + struct TSS32 tss; + struct CONSOLE *cons; + int ds_base, cons_stack; +}; +struct TASKLEVEL { + int running; /*正在运行的任务数量*/ + int now; /*这个变量用来记录当前正在运行的是哪个任务*/ + struct TASK *tasks[MAX_TASKS_LV]; +}; +struct TASKCTL { + int now_lv; /*现在活动中的LEVEL */ + char lv_change; /*在下次任务切换时是否需要改变LEVEL */ + struct TASKLEVEL level[MAX_TASKLEVELS]; + struct TASK tasks0[MAX_TASKS]; +}; +extern struct TASKCTL *taskctl; +extern struct TIMER *task_timer; +struct TASK *task_now(void); +struct TASK *task_init(struct MEMMAN *memman); +struct TASK *task_alloc(void); +void task_run(struct TASK *task, int level, int priority); +void task_switch(void); +void task_sleep(struct TASK *task); + +/* window.c */ +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act); +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l); +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c); +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act); +void change_wtitle8(struct SHEET *sht, char act); + +/* console.c */ +struct CONSOLE { + struct SHEET *sht; + int cur_x, cur_y, cur_c; + struct TIMER *timer; +}; +void console_task(struct SHEET *sheet, int memtotal); +void cons_putchar(struct CONSOLE *cons, int chr, char move); +void cons_newline(struct CONSOLE *cons); +void cons_putstr0(struct CONSOLE *cons, char *s); +void cons_putstr1(struct CONSOLE *cons, char *s, int l); +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal); +void cmd_mem(struct CONSOLE *cons, int memtotal); +void cmd_cls(struct CONSOLE *cons); +void cmd_dir(struct CONSOLE *cons); +void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline); +void cmd_exit(struct CONSOLE *cons, int *fat); +void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal); +void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal); +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline); +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax); +int *inthandler0d(int *esp); +int *inthandler0c(int *esp); +void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col); + +/* file.c */ +struct FILEINFO { + unsigned char name[8], ext[3], type; + char reserve[10]; + unsigned short time, date, clustno; + unsigned int size; +}; +void file_readfat(int *fat, unsigned char *img); +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img); +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max); + +/* bootpack.c */ +struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal); +struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal); diff --git a/27_day/color.c b/27_day/color.c new file mode 100644 index 0000000..c004c14 --- /dev/null +++ b/27_day/color.c @@ -0,0 +1,27 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +int api_getkey(int mode); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win, x, y, r, g, b; + api_initmalloc(); + buf = api_malloc(144 * 164); + win = api_openwin(buf, 144, 164, -1, "color"); + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) { + r = x * 2; + g = y * 2; + b = 0; + buf[(x + 8) + (y + 28) * 144] = 16 + (r / 43) + (g / 43) * 6 + (b / 43) * 36; + } + } + api_refreshwin(win, 8, 28, 136, 156); + api_getkey(1); /*等待按下任意键*/ + api_end(); +} diff --git a/27_day/color2.c b/27_day/color2.c new file mode 100644 index 0000000..c063768 --- /dev/null +++ b/27_day/color2.c @@ -0,0 +1,42 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +int api_getkey(int mode); +void api_end(void); + +unsigned char rgb2pal(int r, int g, int b, int x, int y); + +void HariMain(void) +{ + char *buf; + int win, x, y; + api_initmalloc(); + buf = api_malloc(144 * 164); + win = api_openwin(buf, 144, 164, -1, "color2"); + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) { + buf[(x + 8) + (y + 28) * 144] = rgb2pal(x * 2, y * 2, 0, x, y); + } + } + api_refreshwin(win, 8, 28, 136, 156); + api_getkey(1); /*等待按下任意键*/ + api_end(); +} + +unsigned char rgb2pal(int r, int g, int b, int x, int y) +{ + static int table[4] = { 3, 1, 0, 2 }; + int i; + x &= 1; /*判断是偶数还是奇数*/ + y &= 1; + i = table[x + y * 2]; /*用来生成中间色的常量*/ + r = (r * 21) / 256; /* r为0~20*/ + g = (g * 21) / 256; + b = (b * 21) / 256; + r = (r + i) / 4; /* r为0~5*/ + g = (g + i) / 4; + b = (b + i) / 4; + return 16 + r + g * 6 + b * 36; +} diff --git a/27_day/console.c b/27_day/console.c new file mode 100644 index 0000000..f85ec8c --- /dev/null +++ b/27_day/console.c @@ -0,0 +1,592 @@ +/* 命令行窗口相关 */ + +#include "bootpack.h" +#include +#include + +void console_task(struct SHEET *sheet, int memtotal) +{ + struct TASK *task = task_now(); + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + int i, *fat = (int *) memman_alloc_4k(memman, 4 * 2880); + struct CONSOLE cons; + char cmdline[30]; + cons.sht = sheet; + cons.cur_x = 8; + cons.cur_y = 28; + cons.cur_c = -1; + task->cons = &cons; + + if (sheet != 0) { + cons.timer = timer_alloc(); + timer_init(cons.timer, &task->fifo, 1); + timer_settime(cons.timer, 50); + } + file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); + + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + task_sleep(task); + io_sti(); + } else { + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1) { /*光标用定时器*/ + if (i != 0) { + timer_init(cons.timer, &task->fifo, 0); /*下次置0 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_FFFFFF; + } + } else { + timer_init(cons.timer, &task->fifo, 1); /*下次置1 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_000000; + } + } + timer_settime(cons.timer, 50); + } + if (i == 2) { /*光标ON */ + cons.cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + boxfill8(sheet->buf, sheet->bxsize, COL8_000000, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + cons.cur_c = -1; + } + if (i == 4) { /*点击命令行窗口的“×”按钮*/ + cmd_exit(&cons, fat); + } + if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/ + if (i == 8 + 256) { + /*退格键*/ + if (cons.cur_x > 16) { + /*用空格擦除光标后将光标前移一位*/ + cons_putchar(&cons, ' ', 0); + cons.cur_x -= 8; + } + } else if (i == 10 + 256) { + /*回车键*/ + /*将光标用空格擦除后换行 */ + cons_putchar(&cons, ' ', 0); + cmdline[cons.cur_x / 8 - 2] = 0; + cons_newline(&cons); + cons_runcmd(cmdline, &cons, fat, memtotal); /*运行命令*/ + if (sheet == 0) { + cmd_exit(&cons, fat); + } + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + } else { + /*一般字符*/ + if (cons.cur_x < 240) { + /*显示一个字符之后将光标后移一位*/ + cmdline[cons.cur_x / 8 - 2] = i - 256; + cons_putchar(&cons, i - 256, 1); + } + } + } + /*重新显示光标*/ + if (sheet != 0) { + if (cons.cur_c >= 0) { + boxfill8(sheet->buf, sheet->bxsize, cons.cur_c, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + } + sheet_refresh(sheet, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16); + } + } + } +} + +void cons_putchar(struct CONSOLE *cons, int chr, char move) +{ + char s[2]; + s[0] = chr; + s[1] = 0; + if (s[0] == 0x09) { /*制表符*/ + for (;;) { + if (cons->sht != 0) { + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1); + cons->cur_x += 8; + } + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + if (((cons->cur_x - 8) & 0x1f) == 0) { + break; /*被32整除则break*/ + } + } + } else if (s[0] == 0x0a) { /*换行*/ + cons_newline(cons); + } else if (s[0] == 0x0d) { /*回车*/ + /*先不做任何操作*/ + } else { /*一般字符*/ + if (cons->sht != 0) { + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1); + } + if (move != 0) { + /* move为0时光标不后移*/ + cons->cur_x += 8; + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + } + } + return; +} + +void cons_newline(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + if (cons->cur_y < 28 + 112) { + cons->cur_y += 16; /*到下一行*/ + } else { + /*滚动*/ + if (sheet != 0) { + for (y = 28; y < 28 + 112; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize]; + } + } + for (y = 28 + 112; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + } + } + cons->cur_x = 8; + return; +} + +void cons_putstr0(struct CONSOLE *cons, char *s) +{ + for (; *s != 0; s++) { + cons_putchar(cons, *s, 1); + } + return; +} + +void cons_putstr1(struct CONSOLE *cons, char *s, int l) +{ + int i; + for (i = 0; i < l; i++) { + cons_putchar(cons, s[i], 1); + } + return; +} + +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) +{ + if (strcmp(cmdline, "mem") == 0 && cons->sht != 0) { + cmd_mem(cons, memtotal); + } else if (strcmp(cmdline, "cls") == 0 && cons->sht != 0) { + cmd_cls(cons); + } else if ((strcmp(cmdline, "dir") == 0 || strcmp(cmdline, "ls") == 0) && cons->sht != 0) { + cmd_dir(cons); + } else if (strncmp(cmdline, "type ", 5) == 0 && cons->sht != 0) { + cmd_type(cons, fat, cmdline); + } else if (strcmp(cmdline, "exit") == 0) { + cmd_exit(cons, fat); + } else if (strncmp(cmdline, "start ", 6) == 0) { + cmd_start(cons, cmdline, memtotal); + } else if (strncmp(cmdline, "ncst ", 5) == 0) { + cmd_ncst(cons, cmdline, memtotal); + }else if (cmdline[0] != 0) { + if (cmd_app(cons, fat, cmdline) == 0) { + /*不是命令,不是应用程序,也不是空行*/ + cons_putstr0(cons, "Bad command.\n\n"); + } + } + return; +} + +void cmd_mem(struct CONSOLE *cons, int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + char s[60]; + sprintf(s, "total %dMB\nfree %dKB\n\n", memtotal / (1024 * 1024), memman_total(memman) / 1024); + cons_putstr0(cons, s); + return; +} + +void cmd_cls(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + for (y = 28; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + cons->cur_y = 28; + return; +} + +void cmd_dir(struct CONSOLE *cons) +{ + struct FILEINFO *finfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600); + int i, j; + char s[30]; + for (i = 0; i < 224; i++) { + if (finfo[i].name[0] == 0x00) { + break; + } + if (finfo[i].name[0] != 0xe5) { + if ((finfo[i].type & 0x18) == 0) { + sprintf(s, "filename.ext %7d\n", finfo[i].size); + for (j = 0; j < 8; j++) { + s[j] = finfo[i].name[j]; + } + s[ 9] = finfo[i].ext[0]; + s[10] = finfo[i].ext[1]; + s[11] = finfo[i].ext[2]; + cons_putstr0(cons, s); + } + } + } + cons_newline(cons); + return; +} + +void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct FILEINFO *finfo = file_search(cmdline + 5, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + char *p; + if (finfo != 0) { + /*找到文件的情况*/ + p = (char *) memman_alloc_4k(memman, finfo->size); + file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); + cons_putstr1(cons, p, finfo->size); + memman_free_4k(memman, (int) p, finfo->size); + } else { + /*没有找到文件的情况*/ + cons_putstr0(cons, "File not found.\n"); + } + cons_newline(cons); + return; +} + +void cmd_exit(struct CONSOLE *cons, int *fat) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = task_now(); + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct FIFO32 *fifo = (struct FIFO32 *) *((int *) 0x0fec); + if (cons->sht != 0) { + timer_cancel(cons->timer); + } + memman_free_4k(memman, (int) fat, 4 * 2880); + io_cli(); + if (cons->sht != 0) { + fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); /* 768〜1023 */ + } else { + fifo32_put(fifo, task - taskctl->tasks0 + 1024); /*1024~2023*/ + } + io_sti(); + for (;;) { + task_sleep(task); + } +} + +void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal) +{ + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct SHEET *sht = open_console(shtctl, memtotal); + struct FIFO32 *fifo = &sht->task->fifo; + int i; + sheet_slide(sht, 32, 4); + sheet_updown(sht, shtctl->top); + /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ + for (i = 6; cmdline[i] != 0; i++) { + fifo32_put(fifo, cmdline[i] + 256); + } + fifo32_put(fifo, 10 + 256); /*回车键*/ + cons_newline(cons); + return; +} + +void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal) +{ + struct TASK *task = open_constask(0, memtotal); + struct FIFO32 *fifo = &task->fifo; + int i; + + /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ + for (i = 5; cmdline[i] != 0; i++) { + fifo32_put(fifo, cmdline[i] + 256); + } + fifo32_put(fifo, 10 + 256); /*回车键*/ + cons_newline(cons); + return; +} + +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct FILEINFO *finfo; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + char name[18], *p, *q; + struct TASK *task = task_now(); + int i, segsiz, datsiz, esp, dathrb; + struct SHTCTL *shtctl; + struct SHEET *sht; + + /*根据命令行生成文件名*/ + for (i = 0; i < 13; i++) { + if (cmdline[i] <= ' ') { + break; + } + name[i] = cmdline[i]; + } + name[i] = 0; /*暂且将文件名的后面置为0*/ + + /*寻找文件 */ + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + if (finfo == 0 && name[i - 1] != '.') { + /*由于找不到文件,故在文件名后面加上“.hrb”后重新寻找*/ + name[i ] = '.'; + name[i + 1] = 'H'; + name[i + 2] = 'R'; + name[i + 3] = 'B'; + name[i + 4] = 0; + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + } + + if (finfo != 0) { + /*找到文件的情况*/ + p = (char *) memman_alloc_4k(memman, finfo->size); + file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); + if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) { + segsiz = *((int *) (p + 0x0000)); + esp = *((int *) (p + 0x000c)); + datsiz = *((int *) (p + 0x0010)); + dathrb = *((int *) (p + 0x0014)); + q = (char *) memman_alloc_4k(memman, segsiz); + task->ds_base = (int) q; + set_segmdesc(gdt + task->sel / 8 + 1000, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); + set_segmdesc(gdt + task->sel / 8 + 2000, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); + for (i = 0; i < datsiz; i++) { + q[esp + i] = p[dathrb + i]; + } + start_app(0x1b, task->sel + 1000 * 8, esp, task->sel + 2000 * 8, &(task->tss.esp0)); + shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + for (i = 0; i < MAX_SHEETS; i++) { + sht = &(shtctl->sheets0[i]); + if ((sht->flags & 0x11) == 0x11 && sht->task == task) { + /*找到被应用程序遗留的窗口*/ + sheet_free(sht); /*关闭*/ + } + } + timer_cancelall(&task->fifo); + memman_free_4k(memman, (int) q, segsiz); + } else { + cons_putstr0(cons, ".hrb file format error.\n"); + } + memman_free_4k(memman, (int) p, finfo->size); + cons_newline(cons); + return 1; + } + /*没有找到文件的情况*/ + return 0; +} + +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) +{ + struct TASK *task = task_now(); + int ds_base = task->ds_base; + struct CONSOLE *cons = task->cons; + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct SHEET *sht; + int *reg = &eax + 1; /* eax后面的地址*/ + /*强行改写通过PUSHAD保存的值*/ + /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */ + /* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ + int i; + + if (edx == 1) { + cons_putchar(cons, eax & 0xff, 1); + } else if (edx == 2) { + cons_putstr0(cons, (char *) ebx + ds_base); + } else if (edx == 3) { + cons_putstr1(cons, (char *) ebx + ds_base, ecx); + } else if (edx == 4) { + return &(task->tss.esp0); + } else if (edx == 5) { + sht = sheet_alloc(shtctl); + sht->task = task; + sht->flags |= 0x10; + sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax); + make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0); + sheet_slide(sht, ((shtctl->xsize - esi) / 2) & ~3, (shtctl->ysize - edi) / 2); + sheet_updown(sht, shtctl->top); /*将窗口图层高度指定为当前鼠标所在图层的高度,鼠标移到上层*/ + reg[7] = (int) sht; + } else if (edx == 6) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + putfonts8_asc(sht->buf, sht->bxsize, esi, edi, eax, (char *) ebp + ds_base); + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + ecx * 8, edi + 16); + } + } else if (edx == 7) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + boxfill8(sht->buf, sht->bxsize, ebp, eax, ecx, esi, edi); + if ((ebx & 1) == 0) { + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 8) { + memman_init((struct MEMMAN *) (ebx + ds_base)); + ecx &= 0xfffffff0; /*以16字节为单位*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 9) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + reg[7] = memman_alloc((struct MEMMAN *) (ebx + ds_base), ecx); + } else if (edx == 10) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 11) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + sht->buf[sht->bxsize * edi + esi] = eax; + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + 1, edi + 1); + } + } else if (edx == 12) { + sht = (struct SHEET *) ebx; + sheet_refresh(sht, eax, ecx, esi, edi); + } else if (edx == 13) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + hrb_api_linewin(sht, eax, ecx, esi, edi, ebp); + if ((ebx & 1) == 0) { + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 14) { + sheet_free((struct SHEET *) ebx); + } else if (edx == 15) { + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + if (eax != 0) { + task_sleep(task); /* FIFO为空,休眠并等待*/ + } else { + io_sti(); + reg[7] = -1; + return 0; + } + } + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1) { /*光标用定时器*/ + /*应用程序运行时不需要显示光标,因此总是将下次显示用的值置为1*/ + timer_init(cons->timer, &task->fifo, 1); /*下次置为1*/ + timer_settime(cons->timer, 50); + } + if (i == 2) { /*光标ON */ + cons->cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + cons->cur_c = -1; + } + if (i >= 256) { /*键盘数据(通过任务A)等*/ + reg[7] = i - 256; + return 0; + } + } + } else if (edx == 16) { + reg[7] = (int) timer_alloc(); + ((struct TIMER *) reg[7])->flags2 = 1; /*允许自动取消*/ + } else if (edx == 17) { + timer_init((struct TIMER *) ebx, &task->fifo, eax + 256); + } else if (edx == 18) { + timer_settime((struct TIMER *) ebx, eax); + } else if (edx == 19) { + timer_free((struct TIMER *) ebx); + } else if (edx == 20) { + if (eax == 0) { + i = io_in8(0x61); + io_out8(0x61, i & 0x0d); + } else { + i = 1193180000 / eax; + io_out8(0x43, 0xb6); + io_out8(0x42, i & 0xff); + io_out8(0x42, i >> 8); + i = io_in8(0x61); + io_out8(0x61, (i | 0x03) & 0x0f); + } + } + return 0; +} + +int *inthandler0c(int *esp) +{ + struct TASK *task = task_now(); + struct CONSOLE *cons = task->cons; + char s[30]; + cons_putstr0(cons, "\nINT 0C :\n Stack Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +int *inthandler0d(int *esp) +{ + struct TASK *task = task_now(); + struct CONSOLE *cons = task->cons; + char s[30]; + cons_putstr0(cons, "\nINT 0D :\n General Protected Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col) +{ + int i, x, y, len, dx, dy; + + dx = x1 - x0; + dy = y1 - y0; + x = x0 << 10; + y = y0 << 10; + if (dx < 0) { + dx = - dx; + } + if (dy < 0) { + dy = - dy; + } + if (dx >= dy) { + len = dx + 1; + if (x0 > x1) { + dx = -1024; + } else { + dx = 1024; + } + if (y0 <= y1) { + dy = ((y1 - y0 + 1) << 10) / len; + } else { + dy = ((y1 - y0 - 1) << 10) / len; + } + } else { + len = dy + 1; + if (y0 > y1) { + dy = -1024; + } else { + dy = 1024; + } + if (x0 <= x1) { + dx = ((x1 - x0 + 1) << 10) / len; + } else { + dx = ((x1 - x0 - 1) << 10) / len; + } + } + + for (i = 0; i < len; i++) { + sht->buf[(y >> 10) * sht->bxsize + (x >> 10)] = col; + x += dx; + y += dy; + } + + return; +} diff --git a/27_day/dsctbl.c b/27_day/dsctbl.c new file mode 100644 index 0000000..9ff2c67 --- /dev/null +++ b/27_day/dsctbl.c @@ -0,0 +1,59 @@ +/* GDT、IDT、descriptor table 关系处理 */ + +#include "bootpack.h" + +void init_gdtidt(void) +{ + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *) ADR_IDT; + int i; + + /* GDT初始化 */ + for (i = 0; i <= LIMIT_GDT / 8; i++) { + set_segmdesc(gdt + i, 0, 0, 0); + } + set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW); + set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER); + load_gdtr(LIMIT_GDT, ADR_GDT); + + /* IDT初始化 */ + for (i = 0; i <= LIMIT_IDT / 8; i++) { + set_gatedesc(idt + i, 0, 0, 0); + } + load_idtr(LIMIT_IDT, ADR_IDT); + + /* IDT设置*/ + set_gatedesc(idt + 0x0c, (int) asm_inthandler0c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x0d, (int) asm_inthandler0d, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x40, (int) asm_hrb_api, 2 * 8, AR_INTGATE32 + 0x60); + + return; +} + +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar) +{ + if (limit > 0xfffff) { + ar |= 0x8000; /* G_bit = 1 */ + limit /= 0x1000; + } + sd->limit_low = limit & 0xffff; + sd->base_low = base & 0xffff; + sd->base_mid = (base >> 16) & 0xff; + sd->access_right = ar & 0xff; + sd->limit_high = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0); + sd->base_high = (base >> 24) & 0xff; + return; +} + +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar) +{ + gd->offset_low = offset & 0xffff; + gd->selector = selector; + gd->dw_count = (ar >> 8) & 0xff; + gd->access_right = ar & 0xff; + gd->offset_high = (offset >> 16) & 0xffff; + return; +} diff --git a/27_day/fifo.c b/27_day/fifo.c new file mode 100644 index 0000000..8f28f4b --- /dev/null +++ b/27_day/fifo.c @@ -0,0 +1,63 @@ +/* FIFO */ + +#include "bootpack.h" + +#define FLAGS_OVERRUN 0x0001 + +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task) +/* FIFO缓冲区的初始化*/ +{ + fifo->size = size; + fifo->buf = buf; + fifo->free = size; /*空*/ + fifo->flags = 0; + fifo->p = 0; /*写入位置*/ + fifo->q = 0; /*读取位置*/ + fifo->task = task; /*有数据写入时需要唤醒的任务*/ + return; +} + +int fifo32_put(struct FIFO32 *fifo, int data) +/*向FIFO写入数据并累积起来*/ +{ + if (fifo->free == 0) { + /*没有空余空间,溢出*/ + fifo->flags |= FLAGS_OVERRUN; + return -1; + } + fifo->buf[fifo->p] = data; + fifo->p++; + if (fifo->p == fifo->size) { + fifo->p = 0; + } + fifo->free--; + if (fifo->task != 0) { + if (fifo->task->flags != 2) { /*如果任务处于休眠状态*/ + task_run(fifo->task, -1, 0); /*将任务唤醒*/ + } + } + return 0; +} + +int fifo32_get(struct FIFO32 *fifo) +/*从FIFO取得一个数据*/ +{ + int data; + if (fifo->free == fifo->size) { + /*当缓冲区为空的情况下返回-1*/ + return -1; + } + data = fifo->buf[fifo->q]; + fifo->q++; + if (fifo->q == fifo->size) { + fifo->q = 0; + } + fifo->free++; + return data; +} + +int fifo32_status(struct FIFO32 *fifo) +/*报告已经存储了多少数据*/ +{ + return fifo->size - fifo->free; +} diff --git a/27_day/file.c b/27_day/file.c new file mode 100644 index 0000000..bf9d063 --- /dev/null +++ b/27_day/file.c @@ -0,0 +1,74 @@ +/* 文件相关函数 */ + +#include "bootpack.h" + +void file_readfat(int *fat, unsigned char *img) +/*将磁盘映像中的FAT解压缩 */ +{ + int i, j = 0; + for (i = 0; i < 2880; i += 2) { + fat[i + 0] = (img[j + 0] | img[j + 1] << 8) & 0xfff; + fat[i + 1] = (img[j + 1] >> 4 | img[j + 2] << 4) & 0xfff; + j += 3; + } + return; +} + +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img) +{ + int i; + for (;;) { + if (size <= 512) { + for (i = 0; i < size; i++) { + buf[i] = img[clustno * 512 + i]; + } + break; + } + for (i = 0; i < 512; i++) { + buf[i] = img[clustno * 512 + i]; + } + size -= 512; + buf += 512; + clustno = fat[clustno]; + } + return; +} + +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max) +{ + int i, j; + char s[12]; + for (j = 0; j < 11; j++) { + s[j] = ' '; + } + j = 0; + for (i = 0; name[i] != 0; i++) { + if (j >= 11) { return 0; /*没有找到*/ } + if (name[i] == '.' && j <= 8) { + j = 8; + } else { + s[j] = name[i]; + if ('a' <= s[j] && s[j] <= 'z') { + /*将小写字母转换为大写字母*/ + s[j] -= 0x20; + } + j++; + } + } + for (i = 0; i < max; ) { + if (finfo->name[0] == 0x00) { + break; + } + if ((finfo[i].type & 0x18) == 0) { + for (j = 0; j < 11; j++) { + if (finfo[i].name[j] != s[j]) { + goto next; + } + } + return finfo + i; /*找到文件*/ + } +next: + i++; + } + return 0; /*没有找到*/ +} diff --git a/27_day/graphic.c b/27_day/graphic.c new file mode 100644 index 0000000..4bd6979 --- /dev/null +++ b/27_day/graphic.c @@ -0,0 +1,167 @@ +/* 关于绘图部分的处理 */ + +#include "bootpack.h" + +void init_palette(void) +{ + static unsigned char table_rgb[16 * 3] = { + 0x00, 0x00, 0x00, /* 0:黑 */ + 0xff, 0x00, 0x00, /* 1:梁红 */ + 0x00, 0xff, 0x00, /* 2:亮绿 */ + 0xff, 0xff, 0x00, /* 3:亮黄 */ + 0x00, 0x00, 0xff, /* 4:亮蓝 */ + 0xff, 0x00, 0xff, /* 5:亮紫 */ + 0x00, 0xff, 0xff, /* 6:浅亮蓝 */ + 0xff, 0xff, 0xff, /* 7:白 */ + 0xc6, 0xc6, 0xc6, /* 8:亮灰 */ + 0x84, 0x00, 0x00, /* 9:暗红 */ + 0x00, 0x84, 0x00, /* 10:暗绿 */ + 0x84, 0x84, 0x00, /* 11:暗黄 */ + 0x00, 0x00, 0x84, /* 12:暗青 */ + 0x84, 0x00, 0x84, /* 13:暗紫 */ + 0x00, 0x84, 0x84, /* 14:浅暗蓝 */ + 0x84, 0x84, 0x84 /* 15:暗灰 */ + }; + unsigned char table2[216 * 3]; + int r, g, b; + set_palette(0, 15, table_rgb); + for (b = 0; b < 6; b++) { + for (g = 0; g < 6; g++) { + for (r = 0; r < 6; r++) { + table2[(r + g * 6 + b * 36) * 3 + 0] = r * 51; + table2[(r + g * 6 + b * 36) * 3 + 1] = g * 51; + table2[(r + g * 6 + b * 36) * 3 + 2] = b * 51; + } + } + } + set_palette(16, 231, table2); + return; +} + +void set_palette(int start, int end, unsigned char *rgb) +{ + int i, eflags; + eflags = io_load_eflags(); /* 记录中断许可标志的值 */ + io_cli(); /* 将中断许可标志置为0,禁止中断 */ + io_out8(0x03c8, start); + for (i = start; i <= end; i++) { + io_out8(0x03c9, rgb[0] / 4); + io_out8(0x03c9, rgb[1] / 4); + io_out8(0x03c9, rgb[2] / 4); + rgb += 3; + } + io_store_eflags(eflags); /* 复原中断许可标志 */ + return; +} + +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) +{ + int x, y; + for (y = y0; y <= y1; y++) { + for (x = x0; x <= x1; x++) + vram[y * xsize + x] = c; + } + return; +} + +void init_screen8(char *vram, int x, int y) +{ + boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28); + boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1); + + boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24); + boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4); + boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4); + boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5); + boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3); + boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3); + + boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24); + boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4); + boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3); + boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3); + return; +} + +void putfont8(char *vram, int xsize, int x, int y, char c, char *font) +{ + int i; + char *p, d /* data */; + for (i = 0; i < 16; i++) { + p = vram + (y + i) * xsize + x; + d = font[i]; + if ((d & 0x80) != 0) { p[0] = c; } + if ((d & 0x40) != 0) { p[1] = c; } + if ((d & 0x20) != 0) { p[2] = c; } + if ((d & 0x10) != 0) { p[3] = c; } + if ((d & 0x08) != 0) { p[4] = c; } + if ((d & 0x04) != 0) { p[5] = c; } + if ((d & 0x02) != 0) { p[6] = c; } + if ((d & 0x01) != 0) { p[7] = c; } + } + return; +} + +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s) +{ + extern char hankaku[4096]; + /* C语言中,字符串都是以0x00结尾 */ + for (; *s != 0x00; s++) { + putfont8(vram, xsize, x, y, c, hankaku + *s * 16); + x += 8; + } + return; +} + +void init_mouse_cursor8(char *mouse, char bc) +/* 鼠标的数据准备(16x16) */ +{ + static char cursor[16][16] = { + "**************..", + "*OOOOOOOOOOO*...", + "*OOOOOOOOOO*....", + "*OOOOOOOOO*.....", + "*OOOOOOOO*......", + "*OOOOOOO*.......", + "*OOOOOOO*.......", + "*OOOOOOOO*......", + "*OOOO**OOO*.....", + "*OOO*..*OOO*....", + "*OO*....*OOO*...", + "*O*......*OOO*..", + "**........*OOO*.", + "*..........*OOO*", + "............*OO*", + ".............***" + }; + int x, y; + + for (y = 0; y < 16; y++) { + for (x = 0; x < 16; x++) { + if (cursor[y][x] == '*') { + mouse[y * 16 + x] = COL8_000000; + } + if (cursor[y][x] == 'O') { + mouse[y * 16 + x] = COL8_FFFFFF; + } + if (cursor[y][x] == '.') { + mouse[y * 16 + x] = bc; + } + } + } + return; +} + +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize) +{ + int x, y; + for (y = 0; y < pysize; y++) { + for (x = 0; x < pxsize; x++) { + vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x]; + } + } + return; +} diff --git a/27_day/hankaku.txt b/27_day/hankaku.txt new file mode 100644 index 0000000..62d56f9 --- /dev/null +++ b/27_day/hankaku.txt @@ -0,0 +1,4609 @@ +OSASK̔ptHg𗬗p + +char 0x00 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x01 +........ +........ +..***... +.*...*.. +*.....*. +*.*.*.*. +*.*.*.*. +*.....*. +*.....*. +*.*.*.*. +*..*..*. +.*...*.. +..***... +........ +........ +........ + +char 0x02 +........ +........ +..***... +.*****.. +*******. +**.*.**. +**.*.**. +*******. +*******. +**.*.**. +***.***. +.*****.. +..***... +........ +........ +........ + +char 0x03 +........ +........ +........ +........ +.**.**.. +*******. +*******. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x04 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x05 +........ +........ +........ +........ +...*.... +..***... +.*.*.*.. +*******. +.*.*.*.. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x06 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +**.*.**. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x07 +........ +........ +........ +........ +........ +........ +...**... +..****.. +..****.. +...**... +........ +........ +........ +........ +........ +........ + +char 0x08 +******** +******** +******** +******** +******** +******** +***..*** +**....** +**....** +***..*** +******** +******** +******** +******** +******** +******** + +char 0x09 +........ +........ +........ +........ +........ +..****.. +.**..**. +.*....*. +.*....*. +.**..**. +..****.. +........ +........ +........ +........ +........ + +char 0x0a +******** +******** +******** +******** +******** +**....** +*..**..* +*.****.* +*.****.* +*..**..* +**....** +******** +******** +******** +******** +******** + +char 0x0b +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x0c +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ + +char 0x0d +........ +........ +....**.. +....***. +....*.** +....*.** +....*.*. +....*... +....*... +...**... +.****... +*****... +.***.... +........ +........ +........ + +char 0x0e +........ +........ +...***** +...***** +...*...* +...*...* +...*...* +...*...* +...*...* +...*...* +.***.*** +******** +.**..**. +........ +........ +........ + +char 0x0f +........ +........ +........ +........ +...*.... +.*.*.*.. +..***... +..*.*... +..***... +.*.*.*.. +...*.... +........ +........ +........ +........ +........ + +char 0x10 +........ +*....... +**...... +***..... +****.... +*****... +******.. +*******. +******.. +*****... +****.... +***..... +**...... +*....... +........ +........ + +char 0x11 +........ +......*. +.....**. +....***. +...****. +..*****. +.******. +*******. +.******. +..*****. +...****. +....***. +.....**. +......*. +........ +........ + +char 0x12 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ +........ + +char 0x13 +........ +........ +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +........ +........ +.*...*.. +.*...*.. +........ +........ + +char 0x14 +........ +..*****. +.*..*.*. +*...*.*. +*...*.*. +*...*.*. +*...*.*. +.*..*.*. +..***.*. +....*.*. +....*.*. +....*.*. +....*.*. +....*.*. +........ +........ + +char 0x15 +.*****.. +*.....*. +.*...... +..*..... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +....*... +.....*.. +*.....*. +.*****.. +........ + +char 0x16 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*******. +*******. +........ +........ + +char 0x17 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +.*****.. +........ +........ + +char 0x18 +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x19 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ + +char 0x1a +........ +........ +........ +........ +...*.... +....*... +.....*.. +*******. +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ + +char 0x1b +........ +........ +........ +........ +...*.... +..*..... +.*...... +*******. +.*...... +..*..... +...*.... +........ +........ +........ +........ +........ + +char 0x1c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*....... +*....... +*******. +........ +........ + +char 0x1d +........ +........ +........ +........ +........ +..*.*... +.*...*.. +*******. +.*...*.. +..*.*... +........ +........ +........ +........ +........ +........ + +char 0x1e +........ +........ +........ +........ +...*.... +...*.... +..***... +..***... +.*****.. +.*****.. +*******. +*******. +........ +........ +........ +........ + +char 0x1f +........ +........ +........ +........ +*******. +*******. +.*****.. +.*****.. +..***... +..***... +...*.... +...*.... +........ +........ +........ +........ + +char 0x20 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x21 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ +...*.... +...*.... +........ +........ + +char 0x22 +..*.*... +..*.*... +..*.*... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x23 +........ +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +........ +........ + +char 0x24 +...*.... +..***.*. +.*.*.**. +*..*..*. +*..*..*. +*..*.... +.*.*.... +..***... +...*.*.. +...*..*. +*..*..*. +*..*..*. +**.*.*.. +*.***... +...*.... +...*.... + +char 0x25 +.**...*. +*..*..*. +*..*.*.. +*..*.*.. +.**.*... +....*... +...*.... +...*.... +..*..... +..*.**.. +.*.*..*. +.*.*..*. +*..*..*. +*...**.. +........ +........ + +char 0x26 +........ +.***.... +*...*... +*...*... +*...*... +*..*.... +.**..... +.*...*** +*.*...*. +*..*..*. +*...*.*. +*....*.. +.*...**. +..***..* +........ +........ + +char 0x27 +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x28 +......*. +.....*.. +....*... +....*... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....*... +....*... +.....*.. +......*. +........ + +char 0x29 +*....... +.*...... +..*..... +..*..... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..*..... +..*..... +.*...... +*....... +........ + +char 0x2a +........ +........ +........ +........ +........ +...*.... +*..*..*. +.*.*.*.. +..***... +.*.*.*.. +*..*..*. +...*.... +........ +........ +........ +........ + +char 0x2b +........ +........ +........ +........ +........ +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ +........ +........ + +char 0x2c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x2d +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ +........ +........ +........ +........ +........ +........ + +char 0x2e +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x2f +......*. +......*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*...... +.*...... +*....... +*....... + +char 0x30 +........ +...**... +..*..*.. +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +...**... +........ +........ + +char 0x31 +........ +....*... +...**... +..*.*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +..*****. +........ +........ + +char 0x32 +........ +...**... +..*..*.. +.*....*. +.*....*. +......*. +.....*.. +....*... +...*.... +..*..... +..*..... +.*...... +.*...... +.******. +........ +........ + +char 0x33 +........ +...**... +..*..*.. +.*....*. +......*. +......*. +.....*.. +...**... +.....*.. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x34 +........ +....**.. +....**.. +....**.. +...*.*.. +...*.*.. +...*.*.. +..*..*.. +..*..*.. +.*...*.. +.******. +.....*.. +.....*.. +...****. +........ +........ + +char 0x35 +........ +.*****.. +.*...... +.*...... +.*...... +.*.**... +.**..*.. +......*. +......*. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x36 +........ +...**... +..*..*.. +.*....*. +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x37 +........ +.******. +.*....*. +.*....*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x38 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x39 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..**. +...**.*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x3a +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x3b +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x3c +........ +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +........ + +char 0x3d +........ +........ +........ +........ +........ +........ +*******. +........ +........ +*******. +........ +........ +........ +........ +........ +........ + +char 0x3e +........ +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +........ + +char 0x3f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.....*.. +....*... +...*.... +...*.... +........ +........ +...**... +...**... +........ +........ + +char 0x40 +........ +..***... +.*...*.. +*.....*. +*..**.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*..***.. +*....... +.*...**. +..***... +........ +........ + +char 0x41 +........ +...**... +...**... +...**... +...**... +..*..*.. +..*..*.. +..*..*.. +..*..*.. +.******. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x42 +........ +****.... +.*..*... +.*...*.. +.*...*.. +.*...*.. +.*..*... +.****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +*****... +........ +........ + +char 0x43 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*....... +*....... +*....... +*.....*. +.*....*. +.*...*.. +..***... +........ +........ + +char 0x44 +........ +*****... +.*...*.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...*.. +.*...*.. +*****... +........ +........ + +char 0x45 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x46 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...*.. +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x47 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*..****. +*.....*. +*.....*. +*.....*. +.*....*. +.*...**. +..***... +........ +........ + +char 0x48 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.******. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x49 +........ +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x4a +........ +...***** +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +*....*.. +.*..*... +..**.... +........ + +char 0x4b +........ +***..*** +.*....*. +.*...*.. +.*..*... +.*.*.... +.*.*.... +.**..... +.*.*.... +.*.*.... +.*..*... +.*...*.. +.*....*. +***..*** +........ +........ + +char 0x4c +........ +****.... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x4d +........ +**....** +.*....*. +.**..**. +.**..**. +.**..**. +.*.**.*. +.*.**.*. +.*.**.*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x4e +........ +**...*** +.*....*. +.**...*. +.**...*. +.*.*..*. +.*.*..*. +.*.*..*. +.*..*.*. +.*..*.*. +.*..*.*. +.*...**. +.*...**. +***...*. +........ +........ + +char 0x4f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x50 +........ +*****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +.****... +.*...... +.*...... +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x51 +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*..*..*. +*...*.*. +.*...*.. +..***.*. +........ +........ + +char 0x52 +........ +******.. +.*....*. +.*....*. +.*....*. +.*....*. +.*****.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x53 +........ +..***.*. +.*...**. +*.....*. +*.....*. +*....... +.*...... +..***... +.....*.. +......*. +*.....*. +*.....*. +**...*.. +*.***... +........ +........ + +char 0x54 +........ +*******. +*..*..*. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x55 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..****.. +........ +........ + +char 0x56 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...**... +...**... +........ +........ + +char 0x57 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x58 +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +..*..*.. +..*..*.. +..*..*.. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x59 +........ +***.***. +.*...*.. +.*...*.. +.*...*.. +..*.*... +..*.*... +..*.*... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x5a +........ +*******. +*....*.. +*....*.. +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*....*. +*.....*. +*******. +........ +........ + +char 0x5b +........ +..*****. +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*****. +........ + +char 0x5c +*....... +*....... +.*...... +.*...... +..*..... +..*..... +..*..... +...*.... +...*.... +....*... +....*... +.....*.. +.....*.. +.....*.. +......*. +......*. + +char 0x5d +........ +.*****.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.*****.. +........ + +char 0x5e +........ +...*.... +..*.*... +.*...*.. +*.....*. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x5f +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ + +char 0x60 +...*.... +....*... +.....*.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x61 +........ +........ +........ +........ +........ +.***.... +....*... +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +*...**.. +.***.**. +........ +........ + +char 0x62 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +........ +........ + +char 0x63 +........ +........ +........ +........ +........ +..**.... +.*..**.. +*....*.. +*....*.. +*....... +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x64 +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.**. +........ +........ + +char 0x65 +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +******.. +*....... +*.....*. +.*....*. +..****.. +........ +........ + +char 0x66 +....***. +...*.... +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x67 +........ +........ +........ +........ +........ +..**.**. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +.....*.. +.****... + +char 0x68 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x69 +........ +...*.... +...*.... +........ +........ +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6a +........ +.....*.. +.....*.. +........ +........ +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +....*... +....*... +..**.... + +char 0x6b +**...... +.*...... +.*...... +.*...... +.*...... +.*..***. +.*...*.. +.*..*... +.*.*.... +.**..... +.*.*.... +.*..*... +.*...*.. +***..**. +........ +........ + +char 0x6c +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6d +........ +........ +........ +........ +........ +****.**. +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +**.**.** +........ +........ + +char 0x6e +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x6f +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x70 +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +.*...... +***..... + +char 0x71 +........ +........ +........ +........ +........ +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +....***. + +char 0x72 +........ +........ +........ +........ +........ +**.***.. +.**...*. +.*....*. +.*...... +.*...... +.*...... +.*...... +.*...... +***..... +........ +........ + +char 0x73 +........ +........ +........ +........ +........ +.****.*. +*....**. +*.....*. +**...... +..***... +.....**. +*.....*. +**....*. +*.****.. +........ +........ + +char 0x74 +........ +........ +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....***. +........ +........ + +char 0x75 +........ +........ +........ +........ +........ +**...**. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...**. +..***.** +........ +........ + +char 0x76 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +........ +........ + +char 0x77 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x78 +........ +........ +........ +........ +........ +**...**. +.*...*.. +..*.*... +..*.*... +...*.... +..*.*... +..*.*... +.*...*.. +**...**. +........ +........ + +char 0x79 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...*.... +...*.... +.**..... + +char 0x7a +........ +........ +........ +........ +........ +*******. +*.....*. +*....*.. +....*... +...*.... +..*..... +.*....*. +*.....*. +*******. +........ +........ + +char 0x7b +........ +.....**. +....*... +...*.... +...*.... +...*.... +...*.... +.**..... +...*.... +...*.... +...*.... +...*.... +....*... +.....**. +........ +........ + +char 0x7c +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0x7d +........ +.**..... +...*.... +....*... +....*... +....*... +....*... +.....**. +....*... +....*... +....*... +....*... +...*.... +.**..... +........ +........ + +char 0x7e +........ +.***..*. +*...**.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x7f +........ +........ +........ +........ +...*.... +..*.*... +.*...*.. +*.....*. +*******. +*.....*. +*******. +........ +........ +........ +........ +........ + +char 0x80 +........ +..***... +.*...*.. +*.....*. +*....... +*....... +*....... +*....... +*....... +*....... +*....... +*.....*. +.*...*.. +..***... +...*.... +..*..... + +char 0x81 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x82 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x83 +........ +...*.... +..*.*... +.*...*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x84 +........ +........ +..*..*.. +..*..*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x85 +...*.... +....*... +.....*.. +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x86 +........ +...**... +..*..*.. +...**... +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x87 +........ +........ +........ +........ +........ +..****.. +.*....*. +*....... +*....... +*....... +*....... +*....... +.*....*. +..****.. +....*... +...*.... + +char 0x88 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x89 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8a +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8b +........ +........ +..*..*.. +..*..*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8c +........ +...*.... +..*.*... +.*...*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8d +...*.... +....*... +.....*.. +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8e +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x8f +........ +..***... +.*...*.. +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x90 +....**.. +....*... +...*.... +*******. +*....... +*....... +*....... +*....... +*****... +*....... +*....... +*....... +*....... +*******. +........ +........ + +char 0x91 +........ +........ +........ +........ +........ +.**..... +...***.. +...*..*. +.***..*. +*..****. +*..*.... +*..*.... +*..*..*. +.**.**.. +........ +........ + +char 0x92 +....**.. +...*.... +..*..... +..*.*... +..*.*... +..*.*... +*******. +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +........ +........ + +char 0x93 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x94 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x95 +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x96 +........ +...*.... +..*.*... +.*...*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x97 +...*.... +....*... +.....*.. +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x98 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +.*...*.. +.*...*.. +..*.*... +..*.*... +...*.... +...*.... +..*..... +..*..... +.*...... + +char 0x99 +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9a +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9b +........ +..*.*... +..*.*... +..*.*... +..****.. +.**.*.*. +*.*.*... +*.*.*... +*.*.*... +*.*.*... +*.*.*... +.**.*.*. +..****.. +..*.*... +..*.*... +..*.*... + +char 0x9c +........ +....**.. +...*..*. +..*..... +..*..... +..*..... +******.. +..*..... +..*..... +..*..... +.**..... +*.*..... +*.**..*. +.*..**.. +........ +........ + +char 0x9d +........ +*.....*. +*.....*. +.*...*.. +..*.*... +...*.... +*******. +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x9e +........ +***..... +*..*.... +*...*... +*...*... +*...*... +*..*.*.. +***..*.. +*..***** +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +........ +........ + +char 0x9f +........ +....**.. +...*..*. +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +...*.... +*..*.... +.**..... +........ +........ + +char 0xa0 +....**.. +....*... +...*.... +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0xa1 +....**.. +....*... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xa2 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa3 +....**.. +....*... +...*.... +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0xa4 +........ +...*..*. +..*.*.*. +..*..*.. +........ +*****... +*....*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0xa5 +...*..*. +..*.*.*. +..*..*.. +........ +*.....*. +**....*. +**....*. +*.*...*. +*..*..*. +*..*..*. +*...*.*. +*....**. +*....**. +*.....*. +........ +........ + +char 0xa6 +........ +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +*******. +........ +........ + +char 0xa7 +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +*******. +........ +........ + +char 0xa8 +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +..*..... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*....... +*....... +*....... +........ +........ + +char 0xaa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +......*. +......*. +......*. +........ +........ + +char 0xab +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +.****... +.....*.. +..***... +.*...... +.*****.. +........ +........ + +char 0xac +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +...**... +..*.*... +.*..*... +.*****.. +....*... +........ +........ + +char 0xad +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xae +........ +........ +........ +........ +...*..*. +..*..*.. +.*..*... +*..*.... +*..*.... +.*..*... +..*..*.. +...*..*. +........ +........ +........ +........ + +char 0xaf +........ +........ +........ +........ +*..*.... +.*..*... +..*..*.. +...*..*. +...*..*. +..*..*.. +.*..*... +*..*.... +........ +........ +........ +........ + +char 0xb0 +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. + +char 0xb1 +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. + +char 0xb2 +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* + +char 0xb3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb6 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb7 +........ +........ +........ +........ +........ +........ +........ +******.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb8 +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb9 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xba +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbb +........ +........ +........ +........ +........ +........ +........ +******.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +******.. +........ +........ +........ +........ +........ +........ + +char 0xbd +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******.. +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xbe +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +........ +........ +........ +........ +........ +........ + +char 0xbf +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc0 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc1 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc4 +........ +........ +........ +........ +........ +........ +........ +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc6 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xc8 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xc9 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xca +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xcb +........ +........ +........ +........ +........ +........ +........ +******** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcd +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xce +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcf +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xd0 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd1 +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd3 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xd5 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd6 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd8 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd9 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xda +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xdb +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdc +........ +........ +........ +........ +........ +........ +........ +........ +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdd +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... + +char 0xde +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** + +char 0xdf +******** +******** +******** +******** +******** +******** +******** +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xea +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xeb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xec +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xed +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xee +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xef +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfc +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfd +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfe +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xff +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ diff --git a/27_day/hello.nas b/27_day/hello.nas new file mode 100644 index 0000000..b4e9576 --- /dev/null +++ b/27_day/hello.nas @@ -0,0 +1,16 @@ +[INSTRSET "i486p"] +[BITS 32] + MOV ECX,msg + MOV EDX,1 +putloop: + MOV AL,[CS:ECX] + CMP AL,0 + JE fin + INT 0x40 + ADD ECX,1 + JMP putloop +fin: + MOV EDX,4 + INT 0x40 +msg: + DB "hello",0 diff --git a/27_day/hello2.nas b/27_day/hello2.nas new file mode 100644 index 0000000..5e1e58c --- /dev/null +++ b/27_day/hello2.nas @@ -0,0 +1,9 @@ +[INSTRSET "i486p"] +[BITS 32] + MOV EDX,2 + MOV EBX,msg + INT 0x40 + MOV EDX,4 + INT 0x40 +msg: + DB "hello",0 diff --git a/27_day/hello3.c b/27_day/hello3.c new file mode 100644 index 0000000..97d3236 --- /dev/null +++ b/27_day/hello3.c @@ -0,0 +1,12 @@ +void api_putchar(int c); +void api_end(void); + +void HariMain(void) +{ + api_putchar('h'); + api_putchar('e'); + api_putchar('l'); + api_putchar('l'); + api_putchar('o'); + api_end(); +} diff --git a/27_day/hello4.c b/27_day/hello4.c new file mode 100644 index 0000000..7fb73de --- /dev/null +++ b/27_day/hello4.c @@ -0,0 +1,8 @@ +void api_putstr0(char *s); +void api_end(void); + +void HariMain(void) +{ + api_putstr0("hello, world\n"); + api_end(); +} diff --git a/27_day/hello5.nas b/27_day/hello5.nas new file mode 100644 index 0000000..ee62330 --- /dev/null +++ b/27_day/hello5.nas @@ -0,0 +1,20 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "hello5.nas"] + + GLOBAL _HariMain + +[SECTION .text] + +_HariMain: + MOV EDX,2 + MOV EBX,msg + INT 0x40 + MOV EDX,4 + INT 0x40 + +[SECTION .data] + +msg: + DB "hello, world", 0x0a, 0 diff --git a/27_day/int.c b/27_day/int.c new file mode 100644 index 0000000..54c4c7a --- /dev/null +++ b/27_day/int.c @@ -0,0 +1,26 @@ +/*初始化关系 */ + +#include "bootpack.h" +#include + +void init_pic(void) +/* PIC初始化 */ +{ + io_out8(PIC0_IMR, 0xff ); /* 禁止所有中断 */ + io_out8(PIC1_IMR, 0xff ); /* 禁止所有中断 */ + + io_out8(PIC0_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC0_ICW2, 0x20 ); /* IRQ0-7由INT20-27接收 */ + io_out8(PIC0_ICW3, 1 << 2); /* PIC1由IRQ2相连 */ + io_out8(PIC0_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC1_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC1_ICW2, 0x28 ); /* IRQ8-15由INT28-2f接收 */ + io_out8(PIC1_ICW3, 2 ); /* PIC1由IRQ2连接 */ + io_out8(PIC1_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外全部禁止 */ + io_out8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中断 */ + + return; +} diff --git a/27_day/ipl10.nas b/27_day/ipl10.nas new file mode 100644 index 0000000..7108a21 --- /dev/null +++ b/27_day/ipl10.nas @@ -0,0 +1,109 @@ +; haribote-ipl +; TAB=4 + +CYLS EQU 10 ; 声明CYLS=10 + + ORG 0x7c00 ; 指明程序装载地址 + +; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code + + JMP entry + DB 0x90 + DB "HARIBOTE" ; 启动扇区名称(8字节) + DW 512 ; 每个扇区(sector)大小(必须512字节) + DB 1 ; 簇(cluster)大小(必须为1个扇区) + DW 1 ; FAT起始位置(一般为第一个扇区) + DB 2 ; FAT个数(必须为2) + DW 224 ; 根目录大小(一般为224项) + DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512) + DB 0xf0 ; 磁盘类型(必须为0xf0) + DW 9 ; FAT的长度(必??9扇区) + DW 18 ; 一个磁道(track)有几个扇区(必须为18) + DW 2 ; 磁头数(必??2) + DD 0 ; 不使用分区,必须是0 + DD 2880 ; 重写一次磁盘大小 + DB 0,0,0x29 ; 意义不明(固定) + DD 0xffffffff ; (可能是)卷标号码 + DB "HARIBOTEOS " ; 磁盘的名称(必须为11字?,不足填空格) + DB "FAT12 " ; 磁盘格式名称(必??8字?,不足填空格) + RESB 18 ; 先空出18字节 + +; 程序主体 + +entry: + MOV AX,0 ; 初始化寄存器 + MOV SS,AX + MOV SP,0x7c00 + MOV DS,AX + +; 读取磁盘 + + MOV AX,0x0820 + MOV ES,AX + MOV CH,0 ; 柱面0 + MOV DH,0 ; 磁头0 + MOV CL,2 ; 扇区2 + +readloop: + MOV SI,0 ; 记录失败次数寄存器 + +retry: + MOV AH,0x02 ; AH=0x02 : 读入磁盘 + MOV AL,1 ; 1个扇区 + MOV BX,0 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 调用磁盘BIOS + JNC next ; 没出错则跳转到fin + ADD SI,1 ; 往SI加1 + CMP SI,5 ; 比较SI与5 + JAE error ; SI >= 5 跳转到error + MOV AH,0x00 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 重置驱动器 + JMP retry +next: + MOV AX,ES ; 把内存地址后移0x200(512/16十六进制转换) + ADD AX,0x0020 + MOV ES,AX ; ADD ES,0x020因为没有ADD ES,只能通过AX进行 + ADD CL,1 ; 往CL里面加1 + CMP CL,18 ; 比较CL与18 + JBE readloop ; CL <= 18 跳转到readloop + MOV CL,1 + ADD DH,1 + CMP DH,2 + JB readloop ; DH < 2 跳转到readloop + MOV DH,0 + ADD CH,1 + CMP CH,CYLS + JB readloop ; CH < CYLS 跳转到readloop + +; 读取完毕,跳转到haribote.sys执行! + MOV [0x0ff0],CH ; IPLがどこまで読んだのかをメモ + JMP 0xc200 + +error: + MOV SI,msg + +putloop: + MOV AL,[SI] + ADD SI,1 ; 给SI加1 + CMP AL,0 + JE fin + MOV AH,0x0e ; 显示一个文字 + MOV BX,15 ; 指定字符颜色 + INT 0x10 ; 调用显卡BIOS + JMP putloop + +fin: + HLT ; 让CPU停止,等待指令 + JMP fin ; 无限循环 + +msg: + DB 0x0a, 0x0a ; 换行两次 + DB "load error" + DB 0x0a ; 换行 + DB 0 + + RESB 0x7dfe-$ ; 填写0x00直到0x001fe + + DB 0x55, 0xaa diff --git a/27_day/keyboard.c b/27_day/keyboard.c new file mode 100644 index 0000000..eb5140a --- /dev/null +++ b/27_day/keyboard.c @@ -0,0 +1,44 @@ +/* 键盘控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *keyfifo; +int keydata0; + +void inthandler21(int *esp) +{ + int data; + io_out8(PIC0_OCW2, 0x61); /* 把IRQ-01接收信号结束的信息通知给PIC */ + data = io_in8(PORT_KEYDAT); + fifo32_put(keyfifo, data + keydata0); + return; +} + +#define PORT_KEYSTA 0x0064 +#define KEYSTA_SEND_NOTREADY 0x02 +#define KEYCMD_WRITE_MODE 0x60 +#define KBC_MODE 0x47 + +void wait_KBC_sendready(void) +{ + /* 等待键盘控制电路准备完毕 */ + for (;;) { + if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) { + break; + } + } + return; +} + +void init_keyboard(struct FIFO32 *fifo, int data0) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + keyfifo = fifo; + keydata0 = data0; + /* 键盘控制器的初始化 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, KBC_MODE); + return; +} diff --git a/27_day/lines.c b/27_day/lines.c new file mode 100644 index 0000000..83e7ceb --- /dev/null +++ b/27_day/lines.c @@ -0,0 +1,29 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +void api_closewin(int win); +int api_getkey(int mode); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win, i; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "lines"); + for (i = 0; i < 8; i++) { + api_linewin(win + 1, 8, 26, 77, i * 9 + 26, i); + api_linewin(win + 1, 88, 26, i * 9 + 88, 89, i); + } + api_refreshwin(win, 6, 26, 154, 90); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_closewin(win); + api_end(); +} diff --git a/27_day/make.bat b/27_day/make.bat new file mode 100644 index 0000000..e489766 --- /dev/null +++ b/27_day/make.bat @@ -0,0 +1 @@ +..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/27_day/memory.c b/27_day/memory.c new file mode 100644 index 0000000..54a447a --- /dev/null +++ b/27_day/memory.c @@ -0,0 +1,162 @@ +/* �������֌W */ + +#include "bootpack.h" + +#define EFLAGS_AC_BIT 0x00040000 +#define CR0_CACHE_DISABLE 0x60000000 + +unsigned int memtest(unsigned int start, unsigned int end) +{ + char flg486 = 0; + unsigned int eflg, cr0, i; + + /* 确认CPU是386还是486以上的 */ + eflg = io_load_eflags(); + eflg |= EFLAGS_AC_BIT; /* AC-bit = 1 */ + io_store_eflags(eflg); + eflg = io_load_eflags(); + if ((eflg & EFLAGS_AC_BIT) != 0) { + /* 如果是386,即使设定AC=1,AC的值还会自动回到0 */ + flg486 = 1; + } + + eflg &= ~EFLAGS_AC_BIT; /* AC-bit = 0 */ + io_store_eflags(eflg); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 |= CR0_CACHE_DISABLE; /* 禁止缓存 */ + store_cr0(cr0); + } + + i = memtest_sub(start, end); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 &= ~CR0_CACHE_DISABLE; /* 允许缓存 */ + store_cr0(cr0); + } + + return i; +} + +void memman_init(struct MEMMAN *man) +{ + man->frees = 0; /* 可用信息数目 */ + man->maxfrees = 0; /* 用于观察可用状况:frees的最大值 */ + man->lostsize = 0; /* 释放失败的内存的大小总和 */ + man->losts = 0; /* 释放失败次数 */ + return; +} + +unsigned int memman_total(struct MEMMAN *man) +/* 报告空余内存大小的合计 */ +{ + unsigned int i, t = 0; + for (i = 0; i < man->frees; i++) { + t += man->free[i].size; + } + return t; +} + +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size) +/* 分配 */ +{ + unsigned int i, a; + for (i = 0; i < man->frees; i++) { + if (man->free[i].size >= size) { + /* 找到了足够大的内存 */ + a = man->free[i].addr; + man->free[i].addr += size; + man->free[i].size -= size; + if (man->free[i].size == 0) { + /* 如果free[i]变成了0,就减掉一条可用信息 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 代入结构体 */ + } + } + return a; + } + } + return 0; /* 没有可用空间 */ +} + +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size) +/* 释放 */ +{ + int i, j; + /* 为便于归纳内存,将free[]按照addr的顺序排列 */ + /* 所以,先决定应该放在哪里 */ + for (i = 0; i < man->frees; i++) { + if (man->free[i].addr > addr) { + break; + } + } + /* free[i - 1].addr < addr < free[i].addr */ + if (i > 0) { + /* 前面有可用内存 */ + if (man->free[i - 1].addr + man->free[i - 1].size == addr) { + /* 可以与前面的可用内存归纳到一起 */ + man->free[i - 1].size += size; + if (i < man->frees) { + /* 后面也有 */ + if (addr + size == man->free[i].addr) { + /* 也可以与后面的可用内存归纳到一起 */ + man->free[i - 1].size += man->free[i].size; + /* man->free[i]删除 */ + /* free[i]变成0后归纳到前面去 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 结构体赋值 */ + } + } + } + return 0; /* 成功完成 */ + } + } + /* 不能与前面的可用空间归纳到一起 */ + if (i < man->frees) { + /* 后面还有 */ + if (addr + size == man->free[i].addr) { + /* 可以与后面的内容归纳到一起 */ + man->free[i].addr = addr; + man->free[i].size += size; + return 0; /* 成功完成 */ + } + } + /* 既不能与前面归纳到一起,也不能与后面归纳到一起 */ + if (man->frees < MEMMAN_FREES) { + /* free[i]之后的,向后移动,腾出一点可用空间 */ + for (j = man->frees; j > i; j--) { + man->free[j] = man->free[j - 1]; + } + man->frees++; + if (man->maxfrees < man->frees) { + man->maxfrees = man->frees; /* 更新最大值 */ + } + man->free[i].addr = addr; + man->free[i].size = size; + return 0; /* 成功完成 */ + } + /* 不能往后移动 */ + man->losts++; + man->lostsize += size; + return -1; /* 失败 */ +} + +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size) +{ + unsigned int a; + size = (size + 0xfff) & 0xfffff000; + a = memman_alloc(man, size); + return a; +} + +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size) +{ + int i; + size = (size + 0xfff) & 0xfffff000; + i = memman_free(man, addr, size); + return i; +} diff --git a/27_day/mouse.c b/27_day/mouse.c new file mode 100644 index 0000000..0c6403e --- /dev/null +++ b/27_day/mouse.c @@ -0,0 +1,76 @@ +/* 鼠标控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *mousefifo; +int mousedata0; + +void inthandler2c(int *esp) +/* 来自PS/2鼠标的中断 */ +{ + int data; + io_out8(PIC1_OCW2, 0x64); /* 把IRQ-12接收信号结束的信息通知给PIC1 */ + io_out8(PIC0_OCW2, 0x62); /* 把IRQ-02接收信号结束的信息通知给PIC0 */ + data = io_in8(PORT_KEYDAT); + fifo32_put(mousefifo, data + mousedata0); + return; +} + +#define KEYCMD_SENDTO_MOUSE 0xd4 +#define MOUSECMD_ENABLE 0xf4 + +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + mousefifo = fifo; + mousedata0 = data0; + /* 鼠标有效 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, MOUSECMD_ENABLE); + /* 顺利的话,ACK(0xfa)会被发送*/ + mdec->phase = 0; /* 等待鼠标的0xfa的阶段*/ +return; +} + +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat) +{ + if (mdec->phase == 0) { + /* 等待鼠标的0xfa的阶段 */ + if (dat == 0xfa) { + mdec->phase = 1; + } + return 0; + } + if (mdec->phase == 1) { + /* 等待鼠标第一字节的阶段 */ + mdec->buf[0] = dat; + mdec->phase = 2; + return 0; + } + if (mdec->phase == 2) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[1] = dat; + mdec->phase = 3; + return 0; + } + if (mdec->phase == 3) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[2] = dat; + mdec->phase = 1; + mdec->btn = mdec->buf[0] & 0x07; + mdec->x = mdec->buf[1]; + mdec->y = mdec->buf[2]; + if ((mdec->buf[0] & 0x10) != 0) { + mdec->x |= 0xffffff00; + } + if ((mdec->buf[0] & 0x20) != 0) { + mdec->y |= 0xffffff00; + } + mdec->y = - mdec->y; /* 鼠标的y方向与画面符号相反 */ + return 1; + } + /* 应该不可能到这里来 */ + return -1; +} diff --git a/27_day/mtask.c b/27_day/mtask.c new file mode 100644 index 0000000..b91869d --- /dev/null +++ b/27_day/mtask.c @@ -0,0 +1,202 @@ +/* 多任务管理 */ + +#include "bootpack.h" + +struct TASKCTL *taskctl; +struct TIMER *task_timer; + +struct TASK *task_now(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + return tl->tasks[tl->now]; +} + +void task_add(struct TASK *task) +{ + struct TASKLEVEL *tl = &taskctl->level[task->level]; + tl->tasks[tl->running] = task; + tl->running++; + task->flags = 2; /*活动中*/ + return; +} + +void task_remove(struct TASK *task) +{ + int i; + struct TASKLEVEL *tl = &taskctl->level[task->level]; + + /*寻找task所在的位置*/ + for (i = 0; i < tl->running; i++) { + if (tl->tasks[i] == task) { + /*在这里 */ + break; + } + } + + tl->running--; + if (i < tl->now) { + tl->now--; /*需要移动成员,要相应地处理 */ + } + if (tl->now >= tl->running) { + /*如果now的值出现异常,则进行修正*/ + tl->now = 0; + } + task->flags = 1; /* 休眠中 */ + + /* 移动 */ + for (; i < tl->running; i++) { + tl->tasks[i] = tl->tasks[i + 1]; + } + return; +} + +void task_switchsub(void) +{ + int i; + /*寻找最上层的LEVEL */ + for (i = 0; i < MAX_TASKLEVELS; i++) { + if (taskctl->level[i].running > 0) { + break; /*找到了*/ + } + } + taskctl->now_lv = i; + taskctl->lv_change = 0; + return; +} + +void task_idle(void) +{ + for (;;) { + io_hlt(); + } +} + +struct TASK *task_init(struct MEMMAN *memman) +{ + int i; + struct TASK *task, *idle; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + + + taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL)); + for (i = 0; i < MAX_TASKS; i++) { + taskctl->tasks0[i].flags = 0; + taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8; + set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32); + } + for (i = 0; i < MAX_TASKLEVELS; i++) { + taskctl->level[i].running = 0; + taskctl->level[i].now = 0; + } + + task = task_alloc(); + task->flags = 2; /*活动中标志*/ + task->priority = 2; /* 0.02秒*/ + task->level = 0; /*最高LEVEL */ + task_add(task); + task_switchsub(); /* LEVEL 设置*/ + load_tr(task->sel); + task_timer = timer_alloc(); + timer_settime(task_timer, task->priority); + + idle = task_alloc(); + idle->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024; + idle->tss.eip = (int) &task_idle; + idle->tss.es = 1 * 8; + idle->tss.cs = 2 * 8; + idle->tss.ss = 1 * 8; + idle->tss.ds = 1 * 8; + idle->tss.fs = 1 * 8; + idle->tss.gs = 1 * 8; + task_run(idle, MAX_TASKLEVELS - 1, 1); + + return task; +} + +struct TASK *task_alloc(void) +{ + int i; + struct TASK *task; + for (i = 0; i < MAX_TASKS; i++) { + if (taskctl->tasks0[i].flags == 0) { + task = &taskctl->tasks0[i]; + task->flags = 1; /*正在使用的标志*/ + task->tss.eflags = 0x00000202; /* IF = 1; */ + task->tss.eax = 0; /*这里先置为0*/ + task->tss.ecx = 0; + task->tss.edx = 0; + task->tss.ebx = 0; + task->tss.ebp = 0; + task->tss.esi = 0; + task->tss.edi = 0; + task->tss.es = 0; + task->tss.ds = 0; + task->tss.fs = 0; + task->tss.gs = 0; + task->tss.ldtr = 0; + task->tss.iomap = 0x40000000; + task->tss.ss0 = 0; + return task; + } + } + return 0; /*全部正在使用*/ +} + +void task_run(struct TASK *task, int level, int priority) +{ + if (level < 0) { + level = task->level; /*不改变LEVEL */ + } + if (priority > 0) { + task->priority = priority; + } + if (task->flags == 2 && task->level != level) { + /*改变活动中的LEVEL */ + task_remove(task); /*这里执行之后flag的值会变为1,于是下面的if语句块也会被执行*/ + } + if (task->flags != 2) { + /*从休眠状态唤醒的情形*/ + task->level = level; + task_add(task); + } + taskctl->lv_change = 1; /*下次任务切换时检查LEVEL */ + return; +} + +void task_sleep(struct TASK *task) +{ + struct TASK *now_task; + if (task->flags == 2) { + /*如果处于活动状态*/ + now_task = task_now(); + task_remove(task); /*执行此语句的话flags将变为1 */ + if (task == now_task) { + /*如果是让自己休眠,则需要进行任务切换*/ + task_switchsub(); + now_task = task_now(); /*在设定后获取当前任务的值*/ + farjmp(0, now_task->sel); + } + } + return; +} + + +void task_switch(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + struct TASK *new_task, *now_task = tl->tasks[tl->now]; + tl->now++; + if (tl->now == tl->running) { + tl->now = 0; + } + if (taskctl->lv_change != 0) { + task_switchsub(); + tl = &taskctl->level[taskctl->now_lv]; + } + new_task = tl->tasks[tl->now]; + timer_settime(task_timer, new_task->priority); + if (new_task != now_task) { + farjmp(0, new_task->sel); + } + return; +} diff --git a/27_day/naskfunc.nas b/27_day/naskfunc.nas new file mode 100644 index 0000000..a45775d --- /dev/null +++ b/27_day/naskfunc.nas @@ -0,0 +1,291 @@ +; naskfunc +; TAB=4 + +[FORMAT "WCOFF"] ; 制作目标文件的模式 +[INSTRSET "i486p"] ; 使用到486为止的指令 +[BITS 32] ; 3制作32位模式用的机器语言 +[FILE "naskfunc.nas"] ; 文件名 + + GLOBAL _io_hlt, _io_cli, _io_sti, _io_stihlt + GLOBAL _io_in8, _io_in16, _io_in32 + GLOBAL _io_out8, _io_out16, _io_out32 + GLOBAL _io_load_eflags, _io_store_eflags + GLOBAL _load_gdtr, _load_idtr + GLOBAL _load_cr0, _store_cr0 + GLOBAL _load_tr + GLOBAL _asm_inthandler20, _asm_inthandler21 + GLOBAL _asm_inthandler2c, _asm_inthandler0c + GLOBAL _asm_inthandler0d, _asm_end_app + GLOBAL _memtest_sub + GLOBAL _farjmp, _farcall + GLOBAL _asm_hrb_api, _start_app + EXTERN _inthandler20, _inthandler21 + EXTERN _inthandler2c, _inthandler0d + EXTERN _inthandler0c + EXTERN _hrb_api + +[SECTION .text] + +_io_hlt: ; void io_hlt(void); + HLT + RET + +_io_cli: ; void io_cli(void); + CLI + RET + +_io_sti: ; void io_sti(void); + STI + RET + +_io_stihlt: ; void io_stihlt(void); + STI + HLT + RET + +_io_in8: ; int io_in8(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AL,DX + RET + +_io_in16: ; int io_in16(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AX,DX + RET + +_io_in32: ; int io_in32(int port); + MOV EDX,[ESP+4] ; port + IN EAX,DX + RET + +_io_out8: ; void io_out8(int port, int data); + MOV EDX,[ESP+4] ; port + MOV AL,[ESP+8] ; data + OUT DX,AL + RET + +_io_out16: ; void io_out16(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,AX + RET + +_io_out32: ; void io_out32(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,EAX + RET + +_io_load_eflags: ; int io_load_eflags(void); + PUSHFD ; PUSH EFLAGS + POP EAX + RET + +_io_store_eflags: ; void io_store_eflags(int eflags); + MOV EAX,[ESP+4] + PUSH EAX + POPFD ; POP EFLAGS + RET + +_load_gdtr: ; void load_gdtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LGDT [ESP+6] + RET + +_load_idtr: ; void load_idtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LIDT [ESP+6] + RET + +_load_cr0: ; int load_cr0(void); + MOV EAX,CR0 + RET + +_store_cr0: ; void store_cr0(int cr0); + MOV EAX,[ESP+4] + MOV CR0,EAX + RET + +_load_tr: ; void load_tr(int tr); + LTR [ESP+4] ; tr + RET + +_asm_inthandler20: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler20 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler21: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler21 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler2c: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler2c + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler0c: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0c + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; 在INT 0x0c中也需要这句 + IRETD + +_asm_inthandler0d: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0d + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; INT 0x0d需要这句 + IRETD + +_memtest_sub: ; unsigned int memtest_sub(unsigned int start, unsigned int end) + PUSH EDI ; (由于还要使用EBX, ESI, EDI) + PUSH ESI + PUSH EBX + MOV ESI,0xaa55aa55 ; pat0 = 0xaa55aa55; + MOV EDI,0x55aa55aa ; pat1 = 0x55aa55aa; + MOV EAX,[ESP+12+4] ; i = start; +mts_loop: + MOV EBX,EAX + ADD EBX,0xffc ; p = i + 0xffc; + MOV EDX,[EBX] ; old = *p; + MOV [EBX],ESI ; *p = pat0; + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP EDI,[EBX] ; if (*p != pat1) goto fin; + JNE mts_fin + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP ESI,[EBX] ; if (*p != pat0) goto fin; + JNE mts_fin + MOV [EBX],EDX ; *p = old; + ADD EAX,0x1000 ; i += 0x1000; + CMP EAX,[ESP+12+8] ; if (i <= end) goto mts_loop; + JBE mts_loop + POP EBX + POP ESI + POP EDI + RET +mts_fin: + MOV [EBX],EDX ; *p = old; + POP EBX + POP ESI + POP EDI + RET + +_farjmp: ; void farjmp(int eip, int cs); + JMP FAR [ESP+4] ; eip, cs + RET + +_farcall: ; void farcall(int eip, int cs); + CALL FAR [ESP+4] ; eip, cs + RET + +_asm_hrb_api: + STI + PUSH DS + PUSH ES + PUSHAD ; 用于保存的PUSH + PUSHAD ; 用于向hrb_api传值的PUSH + MOV AX,SS + MOV DS,AX ; 将操作系统用段地址存入DS和ES + MOV ES,AX + CALL _hrb_api + CMP EAX,0 ; 当EAX不为0时程序结束 + JNE _asm_end_app + ADD ESP,32 + POPAD + POP ES + POP DS + IRETD +_asm_end_app: +; EAX为tss.esp0的地址 + MOV ESP,[EAX] + MOV DWORD [EAX+4],0 + POPAD + RET ; 返回cmd_app + +_start_app: ; void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); + PUSHAD ; 将32位寄存器的值全部保存起来 + MOV EAX,[ESP+36] ; 应用程序用EIP + MOV ECX,[ESP+40] ; 应用程序用CS + MOV EDX,[ESP+44] ; 应用程序用ESP + MOV EBX,[ESP+48] ; 应用程序用DS/SS + MOV EBP,[ESP+52] ; tss.esp0的地址 + MOV [EBP ],ESP ; 保存操作系统用ESP + MOV [EBP+4],SS ; 保存操作系统用SS + MOV ES,BX + MOV DS,BX + MOV FS,BX + MOV GS,BX +; 下面调整栈,以免用RETF跳转到应用程序 + OR ECX,3 ; 将应用程序用段号和3进行OR运算 + OR EBX,3 ; 将应用程序用段号和3进行OR运算 + PUSH EBX ; 应用程序的SS + PUSH EDX ; 应用程序的ESP + PUSH ECX ; 应用程序的CS + PUSH EAX ; 应用程序的EIP + RETF +; 应用程序结束后不会回到这里 diff --git a/27_day/noodle.c b/27_day/noodle.c new file mode 100644 index 0000000..13b9033 --- /dev/null +++ b/27_day/noodle.c @@ -0,0 +1,42 @@ +#include + +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +int api_getkey(int mode); +int api_alloctimer(void); +void api_inittimer(int timer, int data); +void api_settimer(int timer, int time); +void api_end(void); + +void HariMain(void) +{ + char *buf, s[12]; + int win, timer, sec = 0, min = 0, hou = 0; + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "noodle"); + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (;;) { + sprintf(s, "%5d:%02d:%02d", hou, min, sec); + api_boxfilwin(win, 28, 27, 115, 41, 7);/*白色*/ + api_putstrwin(win, 28, 27, 0, 11, s); /*黑色*/ + api_settimer(timer, 100); /* 1秒 */ + if (api_getkey(1) != 128) { + break; + } + sec++; + if (sec == 60) { + sec = 0; + min++; + if (min == 60) { + min = 0; + hou++; + } + } + } + api_end(); +} diff --git a/27_day/sheet.c b/27_day/sheet.c new file mode 100644 index 0000000..14aa0ea --- /dev/null +++ b/27_day/sheet.c @@ -0,0 +1,294 @@ +/* sheet */ + +#include "bootpack.h" + +#define SHEET_USE 1 + +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize) +{ + struct SHTCTL *ctl; + int i; + ctl = (struct SHTCTL *) memman_alloc_4k(memman, sizeof (struct SHTCTL)); + if (ctl == 0) { + goto err; + } + ctl->map = (unsigned char *) memman_alloc_4k(memman, xsize * ysize); + if (ctl->map == 0) { + memman_free_4k(memman, (int) ctl, sizeof (struct SHTCTL)); + goto err; + } + ctl->vram = vram; + ctl->xsize = xsize; + ctl->ysize = ysize; + ctl->top = -1; /* 没有一张SHEET */ + for (i = 0; i < MAX_SHEETS; i++) { + ctl->sheets0[i].flags = 0; /* 标记为未使用 */ + ctl->sheets0[i].ctl = ctl; /* 记录所属*/ + } +err: + return ctl; +} + +struct SHEET *sheet_alloc(struct SHTCTL *ctl) +{ + struct SHEET *sht; + int i; + for (i = 0; i < MAX_SHEETS; i++) { + if (ctl->sheets0[i].flags == 0) { + sht = &ctl->sheets0[i]; + sht->flags = SHEET_USE; /* 标记为正在使用*/ + sht->height = -1; /* 隐藏 */ + sht->task = 0; /*不使用自动关闭功能*/ + return sht; + } + } + return 0; /* 所有的SHEET都处于正在使用状态*/ +} + +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv) +{ + sht->buf = buf; + sht->bxsize = xsize; + sht->bysize = ysize; + sht->col_inv = col_inv; + return; +} + +void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1, sid4, *p;; + unsigned char *buf, sid, *map = ctl->map; + struct SHEET *sht; + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= ctl->top; h++) { + sht = ctl->sheets[h]; + sid = sht - ctl->sheets0; /* 将进行了减法计算的地址作为图层号码使用 */ + buf = sht->buf; + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } + if (by1 > sht->bysize) { by1 = sht->bysize; } + if (sht->col_inv == -1) { + if ((sht->vx0 & 3) == 0 && (bx0 & 3) == 0 && (bx1 & 3) == 0) { + /*无透明色图层专用的高速版(4字节型)*/ + bx1 = (bx1 - bx0) / 4; /* MOV次数*/ + sid4 = sid | sid << 8 | sid << 16 | sid << 24; + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + vx = sht->vx0 + bx0; + p = (int *) &map[vy * ctl->xsize + vx]; + for (bx = 0; bx < bx1; bx++) { + p[bx] = sid4; + } + } + } else { + /*无透明色图层专用的高速版(1字节型)*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + map[vy * ctl->xsize + vx] = sid; + } + } + } + } else { + /*有透明色图层用的普通版*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (buf[by * sht->bxsize + bx] != sht->col_inv) { + map[vy * ctl->xsize + vx] = sid; + } + } + } + } + } + return; +} + +void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0, int h1) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1, bx2, sid4, i, i1, *p, *q, *r; + unsigned char *buf, *vram = ctl->vram, *map = ctl->map, sid; + struct SHEET *sht; + + /* 如果refresh的范围超出了画面则修正 */ + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= h1; h++) { + sht = ctl->sheets[h]; + buf = sht->buf; + sid = sht - ctl->sheets0; + + /* 使用vx0~vy1,对bx0~by1进行倒推 */ + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } /* 处理刷新范围在图层外侧 */ + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } /* 应对不同的重叠方式 */ + if (by1 > sht->bysize) { by1 = sht->bysize; } + if ((sht->vx0 & 3) == 0) { + /* 4字节型*/ + i = (bx0 + 3) / 4; /* bx0除以4(小数进位)*/ + i1 = bx1 / 4; /* bx1除以4(小数舍去)*/ + i1 = i1 - i; + sid4 = sid | sid << 8 | sid << 16 | sid << 24; + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1 && (bx & 3) != 0; bx++) { + /*前面被4除多余的部分逐个字节写入*/ + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + vx = sht->vx0 + bx; + p = (int *) &map[vy * ctl->xsize + vx]; + q = (int *) &vram[vy * ctl->xsize + vx]; + r = (int *) &buf[by * sht->bxsize + bx]; + for (i = 0; i < i1; i++) { + /* 4的倍数部分*/ + if (p[i] == sid4) { + q[i] = r[i]; /*估计大多数会是这种情况,因此速度会变快*/ + } else { + bx2 = bx + i * 4; + vx = sht->vx0 + bx2; + if (map[vy * ctl->xsize + vx + 0] == sid) { + vram[vy * ctl->xsize + vx + 0] = buf[by * sht->bxsize + bx2 + 0]; + } + if (map[vy * ctl->xsize + vx + 1] == sid) { + vram[vy * ctl->xsize + vx + 1] = buf[by * sht->bxsize + bx2 + 1]; + } + if (map[vy * ctl->xsize + vx + 2] == sid) { + vram[vy * ctl->xsize + vx + 2] = buf[by * sht->bxsize + bx2 + 2]; + } + if (map[vy * ctl->xsize + vx + 3] == sid) { + vram[vy * ctl->xsize + vx + 3] = buf[by * sht->bxsize + bx2 + 3]; + } + } + } + for (bx += i1 * 4; bx < bx1; bx++) { + /*后面被4除多余的部分逐个字节写入*/ + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + } + } else { + /* 1字节型*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + } + } + } + return; +} + +void sheet_updown(struct SHEET *sht, int height) +{ + struct SHTCTL *ctl = sht->ctl; + int h, old = sht->height; /* 存储设置前的高度信息 */ + if (height > ctl->top + 1) { + height = ctl->top + 1; + } + if (height < -1) { + height = -1; + } + sht->height = height;/* 设定高度 */ + + /* 下面主要是进行sheets[]的重新排列 */ + if (old > height) { /* 比以前低 */ + if (height >= 0) { + /* 把中间的往上提 */ + for (h = old; h > height; h--) { + ctl->sheets[h] = ctl->sheets[h - 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1, old); + } else { /* 隐藏 */ + if (ctl->top > old) { + /* 把上面的降下来 */ + for (h = old; h < ctl->top; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + } + ctl->top--; /* 由于显示中的图层减少了一个,所以最上面的图层高度下降 */ + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0, old - 1); + } + } else if (old < height) { /* 比以前高 */ + if (old >= 0) { + /* 把中间的拉下去 */ + for (h = old; h < height; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + } else { /* 由隐藏状态转为显示状态 */ + /* 将已在上面的提上来 */ + for (h = ctl->top; h >= height; h--) { + ctl->sheets[h + 1] = ctl->sheets[h]; + ctl->sheets[h + 1]->height = h + 1; + } + ctl->sheets[height] = sht; + ctl->top++; /* 由于已显示的图层增加了1个,所以最上面的图层高度增加 */ + } + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height, height); /* 按新图层信息重新绘制画面 */ + } + return; +} + +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1) +{ + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面*/ + sheet_refreshsub(sht->ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1, sht->height, sht->height); + } + return; +} + +void sheet_slide(struct SHEET *sht, int vx0, int vy0) +{ + struct SHTCTL *ctl = sht->ctl; + int old_vx0 = sht->vx0, old_vy0 = sht->vy0; + sht->vx0 = vx0; + sht->vy0 = vy0; + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面 */ + sheet_refreshmap(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0); + sheet_refreshmap(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height); + sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0, sht->height - 1); + sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height, sht->height); + } + return; +} + +void sheet_free(struct SHEET *sht) +{ + if (sht->height >= 0) { + sheet_updown(sht, -1); /* 如果处于显示状态,则先设定为隐藏 */ + } + sht->flags = 0; /* "未使用"标志 */ + return; +} diff --git a/27_day/star1.c b/27_day/star1.c new file mode 100644 index 0000000..8d80ffa --- /dev/null +++ b/27_day/star1.c @@ -0,0 +1,18 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_point(int win, int x, int y, int col); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "star1"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + api_point(win, 75, 59, 3);/*黄色*/ + api_end(); +} diff --git a/27_day/stars.c b/27_day/stars.c new file mode 100644 index 0000000..dc38b2b --- /dev/null +++ b/27_day/stars.c @@ -0,0 +1,24 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_point(int win, int x, int y, int col); +void api_end(void); + +int rand(void); /*产生0~32767之间的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win, x, y, 3);/*黄色*/ + } + api_end(); +} diff --git a/27_day/stars2.c b/27_day/stars2.c new file mode 100644 index 0000000..94a029e --- /dev/null +++ b/27_day/stars2.c @@ -0,0 +1,26 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_point(int win, int x, int y, int col); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_end(void); + +int rand(void); /*产生0~32767的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars2"); + api_boxfilwin(win + 1, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win + 1, x, y, 3);/*黄色*/ + } + api_refreshwin(win, 6, 26, 144, 94); + api_end(); +} diff --git a/27_day/timer.c b/27_day/timer.c new file mode 100644 index 0000000..9018ac8 --- /dev/null +++ b/27_day/timer.c @@ -0,0 +1,169 @@ +/* 定时器 */ + +#include "bootpack.h" + +#define PIT_CTRL 0x0043 +#define PIT_CNT0 0x0040 + +struct TIMERCTL timerctl; + +#define TIMER_FLAGS_ALLOC 1 /* 已配置状态 */ +#define TIMER_FLAGS_USING 2 /* 定时器运行中 */ + +void init_pit(void) +{ + int i; + struct TIMER *t; + io_out8(PIT_CTRL, 0x34); + io_out8(PIT_CNT0, 0x9c); + io_out8(PIT_CNT0, 0x2e); + timerctl.count = 0; + for (i = 0; i < MAX_TIMER; i++) { + timerctl.timers0[i].flags = 0; /* 没有使用 */ + } + t = timer_alloc(); /* 取得一个 */ + t->timeout = 0xffffffff; + t->flags = TIMER_FLAGS_USING; + t->next = 0; /* 末尾 */ + timerctl.t0 = t; /* 因为现在只有哨兵,所以他就在最前面*/ + timerctl.next = 0xffffffff; /* 因为只有哨兵,所以下一个超时时刻就是哨兵的时刻 */ + return; +} + +struct TIMER *timer_alloc(void) +{ + int i; + for (i = 0; i < MAX_TIMER; i++) { + if (timerctl.timers0[i].flags == 0) { + timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; + timerctl.timers0[i].flags2 = 0; + return &timerctl.timers0[i]; + } + } + return 0; /* 没找到 */ +} + +void timer_free(struct TIMER *timer) +{ + timer->flags = 0; /* 未使用 */ + return; +} + +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data) +{ + timer->fifo = fifo; + timer->data = data; + return; +} + +void timer_settime(struct TIMER *timer, unsigned int timeout) +{ + int e; + struct TIMER *t, *s; + timer->timeout = timeout + timerctl.count; + timer->flags = TIMER_FLAGS_USING; + e = io_load_eflags(); + io_cli(); + t = timerctl.t0; + if (timer->timeout <= t->timeout) { + /* 插入最前面的情况 */ + timerctl.t0 = timer; + timer->next = t; /* 下面是设定t */ + timerctl.next = timer->timeout; + io_store_eflags(e); + return; + } + for (;;) { + s = t; + t = t->next; + if (timer->timeout <= t->timeout) { + /* 插入s和t之间的情况 */ + s->next = timer; /* s下一个是timer */ + timer->next = t; /* timer的下一个是t */ + io_store_eflags(e); + return; + } + } +} + +void inthandler20(int *esp) +{ + struct TIMER *timer; + char ts = 0; + io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00接收信号结束的信息通知给PIC */ + timerctl.count++; + if (timerctl.next > timerctl.count) { + return; + } + timer = timerctl.t0; /* 首先把最前面的地址赋给timer */ + for (;;) { + /* 因为timers的定时器都处于运行状态,所以不确认flags */ + if (timer->timeout > timerctl.count) { + break; + } + /* 超时 */ + timer->flags = TIMER_FLAGS_ALLOC; + if (timer != task_timer) { + fifo32_put(timer->fifo, timer->data); + } else { + ts = 1; /* mt_timer超时*/ + } + timer = timer->next; /* 将下一个定时器的地址赋给timer*/ + } + timerctl.t0 = timer; + timerctl.next = timer->timeout; + if (ts != 0) { + task_switch(); + } + return; +} + +int timer_cancel(struct TIMER *timer) +{ + int e; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + if (timer->flags == TIMER_FLAGS_USING) { /*是否需要取消?*/ + if (timer == timerctl.t0) { + /*第一个定时器的取消处理*/ + t = timer->next; + timerctl.t0 = t; + timerctl.next = t->timeout; + } else { + /*非第一个定时器的取消处理*/ + /*找到timer前一个定时器*/ + t = timerctl.t0; + for (;;) { + if (t->next == timer) { + break; + } + t = t->next; + } + t->next = timer->next; + /*将之前“timer的下一个”指向“timer的下一个”*/ + } + timer->flags = TIMER_FLAGS_ALLOC; + io_store_eflags(e); + return 1; /*取消处理成功*/ + } + io_store_eflags(e); + return 0; /*不需要取消处理*/ +} + +void timer_cancelall(struct FIFO32 *fifo) +{ + int e, i; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + for (i = 0; i < MAX_TIMER; i++) { + t = &timerctl.timers0[i]; + if (t->flags != 0 && t->flags2 != 0 && t->fifo == fifo) { + timer_cancel(t); + timer_free(t); + } + } + io_store_eflags(e); + return; +} diff --git a/27_day/walk.c b/27_day/walk.c new file mode 100644 index 0000000..6b106b4 --- /dev/null +++ b/27_day/walk.c @@ -0,0 +1,35 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +void api_closewin(int win); +int api_getkey(int mode); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "walk"); + api_boxfilwin(win, 4, 24, 155, 95, 0);/*黑色*/ + x = 76; + y = 56; + api_putstrwin(win, x, y, 3, 1, "*");/*黄色*/ + for (;;) { + i = api_getkey(1); + api_putstrwin(win, x, y, 0 , 1, "*"); /*用黑色擦除*/ + if (i == '4' && x > 4) { x -= 8; } + if (i == '6' && x < 148) { x += 8; } + if (i == '8' && y > 24) { y -= 8; } + if (i == '2' && y < 80) { y += 8; } + if (i == 0x0a) { break; } /*按回车键结束*/ + api_putstrwin(win, x, y, 3 , 1, "*");/*黄色*/ + } + api_closewin(win); + api_end(); +} diff --git a/27_day/window.c b/27_day/window.c new file mode 100644 index 0000000..4d70578 --- /dev/null +++ b/27_day/window.c @@ -0,0 +1,118 @@ +/* 窗口相关函数 */ + +#include "bootpack.h" + +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act) +{ + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, xsize - 1, 0 ); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, xsize - 2, 1 ); + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, 0, ysize - 1); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, 1, ysize - 2); + boxfill8(buf, xsize, COL8_848484, xsize - 2, 1, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, xsize - 1, 0, xsize - 1, ysize - 1); + boxfill8(buf, xsize, COL8_C6C6C6, 2, 2, xsize - 3, ysize - 3); + boxfill8(buf, xsize, COL8_848484, 1, ysize - 2, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, 0, ysize - 1, xsize - 1, ysize - 1); + make_wtitle8(buf, xsize, title, act); + return; +} + +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act) +{ + static char closebtn[14][16] = { + "OOOOOOOOOOOOOOO@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQQQ@@QQQQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "O$$$$$$$$$$$$$$@", + "@@@@@@@@@@@@@@@@" + }; + int x, y; + char c, tc, tbc; + if (act != 0) { + tc = COL8_FFFFFF; + tbc = COL8_000084; + } else { + tc = COL8_C6C6C6; + tbc = COL8_848484; + } + boxfill8(buf, xsize, tbc, 3, 3, xsize - 4, 20); + putfonts8_asc(buf, xsize, 24, 4, tc, title); + for (y = 0; y < 14; y++) { + for (x = 0; x < 16; x++) { + c = closebtn[y][x]; + if (c == '@') { + c = COL8_000000; + } else if (c == '$') { + c = COL8_848484; + } else if (c == 'Q') { + c = COL8_C6C6C6; + } else { + c = COL8_FFFFFF; + } + buf[(5 + y) * xsize + (xsize - 21 + x)] = c; + } + } + return; +} + +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l) +{ + boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15); + putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); + sheet_refresh(sht, x, y, x + l * 8, y + 16); + return; +} + +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c) +{ + int x1 = x0 + sx, y1 = y0 + sy; + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3); + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1); + boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0); + return; +} + +void change_wtitle8(struct SHEET *sht, char act) +{ + int x, y, xsize = sht->bxsize; + char c, tc_new, tbc_new, tc_old, tbc_old, *buf = sht->buf; + if (act != 0) { + tc_new = COL8_FFFFFF; + tbc_new = COL8_000084; + tc_old = COL8_C6C6C6; + tbc_old = COL8_848484; + } else { + tc_new = COL8_C6C6C6; + tbc_new = COL8_848484; + tc_old = COL8_FFFFFF; + tbc_old = COL8_000084; + } + for (y = 3; y <= 20; y++) { + for (x = 3; x <= xsize - 4; x++) { + c = buf[y * xsize + x]; + if (c == tc_old && x <= xsize - 22) { + c = tc_new; + } else if (c == tbc_old) { + c = tbc_new; + } + buf[y * xsize + x] = c; + } + } + sheet_refresh(sht, 3, 3, xsize, 21); + return; +} diff --git a/27_day/winhelo.c b/27_day/winhelo.c new file mode 100644 index 0000000..6d7fb0a --- /dev/null +++ b/27_day/winhelo.c @@ -0,0 +1,11 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_end(void); + +char buf[150 * 50]; + +void HariMain(void) +{ + int win; + win = api_openwin(buf, 150, 50, -1, "hello"); + api_end(); +} diff --git a/27_day/winhelo2.c b/27_day/winhelo2.c new file mode 100644 index 0000000..f00b007 --- /dev/null +++ b/27_day/winhelo2.c @@ -0,0 +1,15 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_end(void); + +char buf[150 * 50]; + +void HariMain(void) +{ + int win; + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 3); /*黄色*/ + api_putstrwin(win, 28, 28, 0 /*黑色*/, 12, "hello, world"); + api_end(); +} diff --git a/27_day/winhelo3.c b/27_day/winhelo3.c new file mode 100644 index 0000000..527ec01 --- /dev/null +++ b/27_day/winhelo3.c @@ -0,0 +1,19 @@ +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_end(void); + +void HariMain(void) +{ + char *buf; + int win; + + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 6); /*浅蓝色*/ + api_putstrwin(win, 28, 28, 0 , 12, "hello, world");/*黑色*/ + api_end(); +} \ No newline at end of file From 233fe16825034f1869ba09dfcfb822b9485ca250 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Tue, 17 May 2016 11:09:20 +0800 Subject: [PATCH 37/83] =?UTF-8?q?=E5=85=88=E6=9D=A5=E4=BF=AE=E5=A4=8Dbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 27_day/bootpack.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/27_day/bootpack.c b/27_day/bootpack.c index 46f1742..d4ee11f 100644 --- a/27_day/bootpack.c +++ b/27_day/bootpack.c @@ -195,6 +195,7 @@ void HariMain(void) io_cli(); /*强制结束处理时禁止任务切换*/ task->tss.eax = (int) &(task->tss.esp0); task->tss.eip = (int) asm_end_app; + task_run(task, -1, 0); /*为了确实执行结束处理,如果处于休眠状态则唤醒*/ io_sti(); } } @@ -266,6 +267,7 @@ void HariMain(void) io_cli(); /*强制结束处理时禁止任务切换*/ task->tss.eax = (int) &(task->tss.esp0); task->tss.eip = (int) asm_end_app; + task_run(task, -1, 0); io_sti(); } else { /*命令行窗口*/ task = sht->task; From 01bbd98aa82d48cd7365dba63b3b0a5a0b8a8245 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Tue, 17 May 2016 12:24:03 +0800 Subject: [PATCH 38/83] =?UTF-8?q?=E5=BA=94=E7=94=A8=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=97=B6=E5=85=B3=E9=97=AD=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E8=A1=8C=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 27_day/bootpack.c | 14 +++++++++++--- 27_day/console.c | 32 ++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/27_day/bootpack.c b/27_day/bootpack.c index d4ee11f..d4f821a 100644 --- a/27_day/bootpack.c +++ b/27_day/bootpack.c @@ -46,7 +46,7 @@ void HariMain(void) }; int key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; int j, x, y, mmx = -1, mmy = -1, mmx2 = 0; - struct SHEET *sht = 0, *key_win; + struct SHEET *sht = 0, *key_win, *sht2; init_gdtidt(); init_pic(); @@ -195,8 +195,8 @@ void HariMain(void) io_cli(); /*强制结束处理时禁止任务切换*/ task->tss.eax = (int) &(task->tss.esp0); task->tss.eip = (int) asm_end_app; - task_run(task, -1, 0); /*为了确实执行结束处理,如果处于休眠状态则唤醒*/ io_sti(); + task_run(task, -1, 0); /*为了确实执行结束处理,如果处于休眠状态则唤醒*/ } } if (i == 256 + 0x3c && key_shift != 0) { /* Shift+F2 */ @@ -267,10 +267,14 @@ void HariMain(void) io_cli(); /*强制结束处理时禁止任务切换*/ task->tss.eax = (int) &(task->tss.esp0); task->tss.eip = (int) asm_end_app; - task_run(task, -1, 0); io_sti(); + task_run(task, -1, 0); } else { /*命令行窗口*/ task = sht->task; + sheet_updown(sht, -1); /*暂且隐藏该图层*/ + keywin_off(key_win); + key_win = shtctl->sheets[shtctl->top - 1]; + keywin_on(key_win); io_cli(); fifo32_put(&task->fifo, 4); io_sti(); @@ -301,6 +305,10 @@ void HariMain(void) close_console(shtctl->sheets0 + (i - 768)); } else if (1024 <= i && i <= 2023) { close_constask(taskctl->tasks0 + (i - 1024)); + } else if (2024 <= i && i <= 2279) { /*只关闭命令行窗口*/ + sht2 = shtctl->sheets0 + (i - 2024); + memman_free_4k(memman, (int) sht2->buf, 256 * 165); + sheet_free(sht2); } } } diff --git a/27_day/console.c b/27_day/console.c index f85ec8c..536aa8f 100644 --- a/27_day/console.c +++ b/27_day/console.c @@ -17,7 +17,7 @@ void console_task(struct SHEET *sheet, int memtotal) cons.cur_c = -1; task->cons = &cons; - if (sheet != 0) { + if (cons.sht != 0) { cons.timer = timer_alloc(); timer_init(cons.timer, &task->fifo, 1); timer_settime(cons.timer, 50); @@ -35,7 +35,7 @@ void console_task(struct SHEET *sheet, int memtotal) } else { i = fifo32_get(&task->fifo); io_sti(); - if (i <= 1) { /*光标用定时器*/ + if (i <= 1 && cons.sht != 0) { /*光标用定时器*/ if (i != 0) { timer_init(cons.timer, &task->fifo, 0); /*下次置0 */ if (cons.cur_c >= 0) { @@ -53,7 +53,10 @@ void console_task(struct SHEET *sheet, int memtotal) cons.cur_c = COL8_FFFFFF; } if (i == 3) { /*光标OFF */ - boxfill8(sheet->buf, sheet->bxsize, COL8_000000, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + if (cons.sht != 0) { + boxfill8(cons.sht->buf, cons.sht->bxsize, COL8_000000, + cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + } cons.cur_c = -1; } if (i == 4) { /*点击命令行窗口的“×”按钮*/ @@ -74,7 +77,7 @@ void console_task(struct SHEET *sheet, int memtotal) cmdline[cons.cur_x / 8 - 2] = 0; cons_newline(&cons); cons_runcmd(cmdline, &cons, fat, memtotal); /*运行命令*/ - if (sheet == 0) { + if (cons.sht == 0) { cmd_exit(&cons, fat); } /*显示提示符*/ @@ -89,11 +92,12 @@ void console_task(struct SHEET *sheet, int memtotal) } } /*重新显示光标*/ - if (sheet != 0) { + if (cons.sht != 0) { if (cons.cur_c >= 0) { - boxfill8(sheet->buf, sheet->bxsize, cons.cur_c, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + boxfill8(cons.sht->buf, cons.sht->bxsize, cons.cur_c, + cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); } - sheet_refresh(sheet, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16); + sheet_refresh(cons.sht, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16); } } } @@ -108,8 +112,8 @@ void cons_putchar(struct CONSOLE *cons, int chr, char move) for (;;) { if (cons->sht != 0) { putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1); - cons->cur_x += 8; } + cons->cur_x += 8; if (cons->cur_x == 8 + 240) { cons_newline(cons); } @@ -194,8 +198,8 @@ void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) } else if (strncmp(cmdline, "start ", 6) == 0) { cmd_start(cons, cmdline, memtotal); } else if (strncmp(cmdline, "ncst ", 5) == 0) { - cmd_ncst(cons, cmdline, memtotal); - }else if (cmdline[0] != 0) { + cmd_ncst(cons, cmdline, memtotal); + } else if (cmdline[0] != 0) { if (cmd_app(cons, fat, cmdline) == 0) { /*不是命令,不是应用程序,也不是空行*/ cons_putstr0(cons, "Bad command.\n\n"); @@ -403,6 +407,7 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int struct CONSOLE *cons = task->cons; struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); struct SHEET *sht; + struct FIFO32 *sys_fifo = (struct FIFO32 *) *((int *) 0x0fec); int *reg = &eax + 1; /* eax后面的地址*/ /*强行改写通过PUSHAD保存的值*/ /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */ @@ -490,6 +495,13 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int if (i == 3) { /*光标OFF */ cons->cur_c = -1; } + if (i == 4) { /*只关闭命令行窗口*/ + timer_cancel(cons->timer); + io_cli(); + fifo32_put(sys_fifo, cons->sht - shtctl->sheets0 + 2024); /*2024~2279*/ + cons->sht = 0; + io_sti(); + } if (i >= 256) { /*键盘数据(通过任务A)等*/ reg[7] = i - 256; return 0; From f3f9a6c1785b9d3c0742690f634a644dfeba9828 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Tue, 17 May 2016 12:30:15 +0800 Subject: [PATCH 39/83] =?UTF-8?q?=E4=BF=9D=E6=8A=A4=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=EF=BC=881=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 27_day/Makefile | 10 +++++++++- 27_day/crack7.nas | 28 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 27_day/crack7.nas diff --git a/27_day/Makefile b/27_day/Makefile index 8714cad..2bfddd0 100644 --- a/27_day/Makefile +++ b/27_day/Makefile @@ -164,10 +164,17 @@ color2.bim : color2.obj a_nask.obj Makefile color2.hrb : color2.bim Makefile $(BIM2HRB) color2.bim color2.hrb 56k +crack7.bim : crack7.obj Makefile + $(OBJ2BIM) @$(RULEFILE) out:crack7.bim stack:1k map:crack7.map crack7.obj + +crack7.hrb : crack7.bim Makefile + $(BIM2HRB) crack7.bim crack7.hrb 0k + haribote.img : ipl10.bin haribote.sys Makefile \ hello.hrb hello2.hrb a.hrb hello3.hrb hello4.hrb hello5.hrb \ winhelo.hrb winhelo2.hrb winhelo3.hrb star1.hrb stars.hrb stars2.hrb \ - lines.hrb walk.hrb noodle.hrb beepdown.hrb color.hrb color2.hrb + lines.hrb walk.hrb noodle.hrb beepdown.hrb color.hrb color2.hrb \ + crack7.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:ipl10.bin len:512 from:0 to:0 \ copy from:haribote.sys to:@: \ @@ -191,6 +198,7 @@ haribote.img : ipl10.bin haribote.sys Makefile \ copy from:beepdown.hrb to:@: \ copy from:color.hrb to:@: \ copy from:color2.hrb to:@: \ + copy from:crack7.hrb to:@: \ imgout:haribote.img # 其他指令 diff --git a/27_day/crack7.nas b/27_day/crack7.nas new file mode 100644 index 0000000..134090f --- /dev/null +++ b/27_day/crack7.nas @@ -0,0 +1,28 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "crack7.nas"] + + GLOBAL _HariMain + +[SECTION .text] + +_HariMain: + MOV AX,1005*8 + MOV DS,AX + CMP DWORD [DS:0x0004],'Hari' + JNE fin ; 不是应用程序,因此不执行任何操作 + + MOV ECX,[DS:0x0000] ; 读取该应用程序数据段的大小 + MOV AX,2005*8 + MOV DS,AX + +crackloop: ; 整个用123填充 + ADD ECX,-1 + MOV BYTE [DS:ECX],123 + CMP ECX,0 + JNE crackloop + +fin: ; 结束 + MOV EDX,4 + INT 0x40 From 575c4ffce8fe1269ce7847552563516604ff56be Mon Sep 17 00:00:00 2001 From: Yourtion Date: Tue, 17 May 2016 12:39:47 +0800 Subject: [PATCH 40/83] =?UTF-8?q?=E4=BF=9D=E6=8A=A4=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=EF=BC=882=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 27_day/bootpack.h | 12 +++++++----- 27_day/console.c | 6 +++--- 27_day/mtask.c | 3 ++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/27_day/bootpack.h b/27_day/bootpack.h index 2195e24..f4ec328 100644 --- a/27_day/bootpack.h +++ b/27_day/bootpack.h @@ -88,15 +88,16 @@ struct GATE_DESCRIPTOR { void init_gdtidt(void); void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar); void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar); -#define ADR_IDT 0x0026f800 -#define LIMIT_IDT 0x000007ff -#define ADR_GDT 0x00270000 -#define LIMIT_GDT 0x0000ffff +#define ADR_IDT 0x0026f800 +#define LIMIT_IDT 0x000007ff +#define ADR_GDT 0x00270000 +#define LIMIT_GDT 0x0000ffff #define ADR_BOTPAK 0x00280000 #define LIMIT_BOTPAK 0x0007ffff #define AR_DATA32_RW 0x4092 #define AR_CODE32_ER 0x409a -#define AR_TSS32 0x0089 +#define AR_LDT 0x0082 +#define AR_TSS32 0x0089 #define AR_INTGATE32 0x008e /* int.c */ @@ -210,6 +211,7 @@ struct TASK { int level, priority; /* 优先级 */ struct FIFO32 fifo; struct TSS32 tss; + struct SEGMENT_DESCRIPTOR ldt[2]; struct CONSOLE *cons; int ds_base, cons_stack; }; diff --git a/27_day/console.c b/27_day/console.c index 536aa8f..6ce8fdc 100644 --- a/27_day/console.c +++ b/27_day/console.c @@ -373,12 +373,12 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) dathrb = *((int *) (p + 0x0014)); q = (char *) memman_alloc_4k(memman, segsiz); task->ds_base = (int) q; - set_segmdesc(gdt + task->sel / 8 + 1000, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); - set_segmdesc(gdt + task->sel / 8 + 2000, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); + set_segmdesc(task->ldt + 0, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); + set_segmdesc(task->ldt + 1, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); for (i = 0; i < datsiz; i++) { q[esp + i] = p[dathrb + i]; } - start_app(0x1b, task->sel + 1000 * 8, esp, task->sel + 2000 * 8, &(task->tss.esp0)); + start_app(0x1b, 0 * 8 + 4, esp, 1 * 8 + 4, &(task->tss.esp0)); shtctl = (struct SHTCTL *) *((int *) 0x0fe4); for (i = 0; i < MAX_SHEETS; i++) { sht = &(shtctl->sheets0[i]); diff --git a/27_day/mtask.c b/27_day/mtask.c index b91869d..f67b935 100644 --- a/27_day/mtask.c +++ b/27_day/mtask.c @@ -82,7 +82,9 @@ struct TASK *task_init(struct MEMMAN *memman) for (i = 0; i < MAX_TASKS; i++) { taskctl->tasks0[i].flags = 0; taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8; + taskctl->tasks0[i].tss.ldtr = (TASK_GDT0 + MAX_TASKS + i) * 8; set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32); + set_segmdesc(gdt + TASK_GDT0 + MAX_TASKS + i, 15, (int) taskctl->tasks0[i].ldt, AR_LDT); } for (i = 0; i < MAX_TASKLEVELS; i++) { taskctl->level[i].running = 0; @@ -133,7 +135,6 @@ struct TASK *task_alloc(void) task->tss.ds = 0; task->tss.fs = 0; task->tss.gs = 0; - task->tss.ldtr = 0; task->tss.iomap = 0x40000000; task->tss.ss0 = 0; return task; From d63b8acd911fdd04d5efa5c18abeb3ca18c49a34 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Tue, 17 May 2016 12:44:39 +0800 Subject: [PATCH 41/83] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E7=9A=84=E5=A4=A7=E5=B0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 27_day/Makefile | 71 +++++++------- 27_day/a_nask.nas | 230 ---------------------------------------------- 27_day/api001.nas | 14 +++ 27_day/api002.nas | 16 ++++ 27_day/api003.nas | 17 ++++ 27_day/api004.nas | 12 +++ 27_day/api005.nas | 24 +++++ 27_day/api006.nas | 27 ++++++ 27_day/api007.nas | 27 ++++++ 27_day/api008.nas | 20 ++++ 27_day/api009.nas | 17 ++++ 27_day/api010.nas | 18 ++++ 27_day/api011.nas | 23 +++++ 27_day/api012.nas | 24 +++++ 27_day/api013.nas | 27 ++++++ 27_day/api014.nas | 16 ++++ 27_day/api015.nas | 14 +++ 27_day/api016.nas | 13 +++ 27_day/api017.nas | 17 ++++ 27_day/api018.nas | 17 ++++ 27_day/api019.nas | 16 ++++ 27_day/api020.nas | 14 +++ 22 files changed, 411 insertions(+), 263 deletions(-) delete mode 100644 27_day/a_nask.nas create mode 100644 27_day/api001.nas create mode 100644 27_day/api002.nas create mode 100644 27_day/api003.nas create mode 100644 27_day/api004.nas create mode 100644 27_day/api005.nas create mode 100644 27_day/api006.nas create mode 100644 27_day/api007.nas create mode 100644 27_day/api008.nas create mode 100644 27_day/api009.nas create mode 100644 27_day/api010.nas create mode 100644 27_day/api011.nas create mode 100644 27_day/api012.nas create mode 100644 27_day/api013.nas create mode 100644 27_day/api014.nas create mode 100644 27_day/api015.nas create mode 100644 27_day/api016.nas create mode 100644 27_day/api017.nas create mode 100644 27_day/api018.nas create mode 100644 27_day/api019.nas create mode 100644 27_day/api020.nas diff --git a/27_day/Makefile b/27_day/Makefile index 2bfddd0..719f71d 100644 --- a/27_day/Makefile +++ b/27_day/Makefile @@ -2,6 +2,11 @@ OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \ int.obj fifo.obj keyboard.obj mouse.obj memory.obj sheet.obj timer.obj \ mtask.obj window.obj console.obj file.obj +OBJS_API = api001.obj api002.obj api003.obj api004.obj api005.obj api006.obj \ + api007.obj api008.obj api009.obj api010.obj api011.obj api012.obj \ + api013.obj api014.obj api015.obj api016.obj api017.obj api018.obj \ + api019.obj api020.obj + TOOLPATH = ../z_tools/ INCPATH = ../z_tools/haribote/ @@ -55,21 +60,21 @@ hello.hrb : hello.nas Makefile hello2.hrb : hello2.nas Makefile $(NASK) hello2.nas hello2.hrb hello2.lst -a.bim : a.obj a_nask.obj Makefile - $(OBJ2BIM) @$(RULEFILE) out:a.bim map:a.map a.obj a_nask.obj +a.bim : a.obj $(OBJS_API) Makefile + $(OBJ2BIM) @$(RULEFILE) out:a.bim map:a.map a.obj $(OBJS_API) a.hrb : a.bim Makefile $(BIM2HRB) a.bim a.hrb 0 -hello3.bim : hello3.obj a_nask.obj Makefile - $(OBJ2BIM) @$(RULEFILE) out:hello3.bim map:hello3.map hello3.obj a_nask.obj +hello3.bim : hello3.obj $(OBJS_API) Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello3.bim map:hello3.map hello3.obj $(OBJS_API) hello3.hrb : hello3.bim Makefile $(BIM2HRB) hello3.bim hello3.hrb 0 -hello4.bim : hello4.obj a_nask.obj Makefile +hello4.bim : hello4.obj $(OBJS_API) Makefile $(OBJ2BIM) @$(RULEFILE) out:hello4.bim stack:1k map:hello4.map \ - hello4.obj a_nask.obj + hello4.obj $(OBJS_API) hello4.hrb : hello4.bim Makefile $(BIM2HRB) hello4.bim hello4.hrb 0 @@ -80,86 +85,86 @@ hello5.bim : hello5.obj Makefile hello5.hrb : hello5.bim Makefile $(BIM2HRB) hello5.bim hello5.hrb 0 -winhelo.bim : winhelo.obj a_nask.obj Makefile +winhelo.bim : winhelo.obj $(OBJS_API) Makefile $(OBJ2BIM) @$(RULEFILE) out:winhelo.bim stack:1k map:winhelo.map \ - winhelo.obj a_nask.obj + winhelo.obj $(OBJS_API) winhelo.hrb : winhelo.bim Makefile $(BIM2HRB) winhelo.bim winhelo.hrb 0 -winhelo2.bim : winhelo2.obj a_nask.obj Makefile +winhelo2.bim : winhelo2.obj $(OBJS_API) Makefile $(OBJ2BIM) @$(RULEFILE) out:winhelo2.bim stack:1k map:winhelo2.map \ - winhelo2.obj a_nask.obj + winhelo2.obj $(OBJS_API) winhelo2.hrb : winhelo2.bim Makefile $(BIM2HRB) winhelo2.bim winhelo2.hrb 0 -winhelo3.bim : winhelo3.obj a_nask.obj Makefile +winhelo3.bim : winhelo3.obj $(OBJS_API) Makefile $(OBJ2BIM) @$(RULEFILE) out:winhelo3.bim stack:1k map:winhelo3.map \ - winhelo3.obj a_nask.obj + winhelo3.obj $(OBJS_API) winhelo3.hrb : winhelo3.bim Makefile $(BIM2HRB) winhelo3.bim winhelo3.hrb 40k -star1.bim : star1.obj a_nask.obj Makefile +star1.bim : star1.obj $(OBJS_API) Makefile $(OBJ2BIM) @$(RULEFILE) out:star1.bim stack:1k map:star1.map \ - star1.obj a_nask.obj + star1.obj $(OBJS_API) star1.hrb : star1.bim Makefile $(BIM2HRB) star1.bim star1.hrb 47k -stars.bim : stars.obj a_nask.obj Makefile +stars.bim : stars.obj $(OBJS_API) Makefile $(OBJ2BIM) @$(RULEFILE) out:stars.bim stack:1k map:stars.map \ - stars.obj a_nask.obj + stars.obj $(OBJS_API) stars.hrb : stars.bim Makefile $(BIM2HRB) stars.bim stars.hrb 47k -stars2.bim : stars2.obj a_nask.obj Makefile +stars2.bim : stars2.obj $(OBJS_API) Makefile $(OBJ2BIM) @$(RULEFILE) out:stars2.bim stack:1k map:stars2.map \ - stars2.obj a_nask.obj + stars2.obj $(OBJS_API) stars2.hrb : stars2.bim Makefile $(BIM2HRB) stars2.bim stars2.hrb 47k -lines.bim : lines.obj a_nask.obj Makefile +lines.bim : lines.obj $(OBJS_API) Makefile $(OBJ2BIM) @$(RULEFILE) out:lines.bim stack:1k map:lines.map \ - lines.obj a_nask.obj + lines.obj $(OBJS_API) lines.hrb : lines.bim Makefile $(BIM2HRB) lines.bim lines.hrb 48k -walk.bim : walk.obj a_nask.obj Makefile +walk.bim : walk.obj $(OBJS_API) Makefile $(OBJ2BIM) @$(RULEFILE) out:walk.bim stack:1k map:walk.map \ - walk.obj a_nask.obj + walk.obj $(OBJS_API) walk.hrb : walk.bim Makefile $(BIM2HRB) walk.bim walk.hrb 48k -noodle.bim : noodle.obj a_nask.obj Makefile +noodle.bim : noodle.obj $(OBJS_API) Makefile $(OBJ2BIM) @$(RULEFILE) out:noodle.bim stack:1k map:noodle.map \ - noodle.obj a_nask.obj + noodle.obj $(OBJS_API) noodle.hrb : noodle.bim Makefile $(BIM2HRB) noodle.bim noodle.hrb 40k -beepdown.bim : beepdown.obj a_nask.obj Makefile +beepdown.bim : beepdown.obj $(OBJS_API) Makefile $(OBJ2BIM) @$(RULEFILE) out:beepdown.bim stack:1k map:beepdown.map \ - beepdown.obj a_nask.obj + beepdown.obj $(OBJS_API) beepdown.hrb : beepdown.bim Makefile $(BIM2HRB) beepdown.bim beepdown.hrb 40k -color.bim : color.obj a_nask.obj Makefile +color.bim : color.obj $(OBJS_API) Makefile $(OBJ2BIM) @$(RULEFILE) out:color.bim stack:1k map:color.map \ - color.obj a_nask.obj + color.obj $(OBJS_API) color.hrb : color.bim Makefile $(BIM2HRB) color.bim color.hrb 56k -color2.bim : color2.obj a_nask.obj Makefile +color2.bim : color2.obj $(OBJS_API) Makefile $(OBJ2BIM) @$(RULEFILE) out:color2.bim stack:1k map:color2.map \ - color2.obj a_nask.obj + color2.obj $(OBJS_API) color2.hrb : color2.bim Makefile $(BIM2HRB) color2.bim color2.hrb 56k @@ -230,9 +235,9 @@ clean : -$(DEL) *.bin -$(DEL) *.lst -$(DEL) *.obj - -$(DEL) bootpack.map - -$(DEL) bootpack.bim - -$(DEL) bootpack.hrb + -$(DEL) *.map + -$(DEL) *.bim + -$(DEL) *.hrb -$(DEL) haribote.sys src_only : diff --git a/27_day/a_nask.nas b/27_day/a_nask.nas deleted file mode 100644 index 9e63654..0000000 --- a/27_day/a_nask.nas +++ /dev/null @@ -1,230 +0,0 @@ -[FORMAT "WCOFF"] ; 生成对象文件的模式 -[INSTRSET "i486p"] ; 表示使用486兼容指令集 -[BITS 32] ; 生成32位模式机器语言 -[FILE "a_nask.nas"] ; 源文件名信息 - - GLOBAL _api_putchar - GLOBAL _api_putstr0 - GLOBAL _api_end - GLOBAL _api_openwin - GLOBAL _api_putstrwin - GLOBAL _api_boxfilwin - GLOBAL _api_initmalloc - GLOBAL _api_malloc - GLOBAL _api_free - GLOBAL _api_point - GLOBAL _api_refreshwin - GLOBAL _api_linewin - GLOBAL _api_closewin - GLOBAL _api_getkey - GLOBAL _api_alloctimer - GLOBAL _api_inittimer - GLOBAL _api_settimer - GLOBAL _api_freetimer - GLOBAL _api_beep - -[SECTION .text] - -_api_putchar: ; void api_putchar(int c); - MOV EDX,1 - MOV AL,[ESP+4] ; c - INT 0x40 - RET - -_api_putstr0: ; void api_putstr0(char *s); - PUSH EBX - MOV EDX,2 - MOV EBX,[ESP+8] ; s - INT 0x40 - POP EBX - RET - -_api_end: ; void api_end(void); - MOV EDX,4 - INT 0x40 - -_api_openwin: ; int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); - PUSH EDI - PUSH ESI - PUSH EBX - MOV EDX,5 - MOV EBX,[ESP+16] ; buf - MOV ESI,[ESP+20] ; xsiz - MOV EDI,[ESP+24] ; ysiz - MOV EAX,[ESP+28] ; col_inv - MOV ECX,[ESP+32] ; title - INT 0x40 - POP EBX - POP ESI - POP EDI - RET - -_api_putstrwin: ; void api_putstrwin(int win, int x, int y, int col, int len, char *str); - PUSH EDI - PUSH ESI - PUSH EBP - PUSH EBX - MOV EDX,6 - MOV EBX,[ESP+20] ; win - MOV ESI,[ESP+24] ; x - MOV EDI,[ESP+28] ; y - MOV EAX,[ESP+32] ; col - MOV ECX,[ESP+36] ; len - MOV EBP,[ESP+40] ; str - INT 0x40 - POP EBX - POP EBP - POP ESI - POP EDI - RET - -_api_boxfilwin: ; void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); - PUSH EDI - PUSH ESI - PUSH EBP - PUSH EBX - MOV EDX,7 - MOV EBX,[ESP+20] ; win - MOV EAX,[ESP+24] ; x0 - MOV ECX,[ESP+28] ; y0 - MOV ESI,[ESP+32] ; x1 - MOV EDI,[ESP+36] ; y1 - MOV EBP,[ESP+40] ; col - INT 0x40 - POP EBX - POP EBP - POP ESI - POP EDI - RET - -_api_initmalloc: ; void api_initmalloc(void); - PUSH EBX - MOV EDX,8 - MOV EBX,[CS:0x0020] ; malloc内存空间的地址 - MOV EAX,EBX - ADD EAX,32*1024 ; 加上32KB - MOV ECX,[CS:0x0000] ; 数据段的大小 - SUB ECX,EAX - INT 0x40 - POP EBX - RET - -_api_malloc: ; char *api_malloc(int size); - PUSH EBX - MOV EDX,9 - MOV EBX,[CS:0x0020] - MOV ECX,[ESP+8] ; size - INT 0x40 - POP EBX - RET - -_api_free: ; void api_free(char *addr, int size); - PUSH EBX - MOV EDX,10 - MOV EBX,[CS:0x0020] - MOV EAX,[ESP+ 8] ; addr - MOV ECX,[ESP+12] ; size - INT 0x40 - POP EBX - RET - -_api_point: ; void api_point(int win, int x, int y, int col); - PUSH EDI - PUSH ESI - PUSH EBX - MOV EDX,11 - MOV EBX,[ESP+16] ; win - MOV ESI,[ESP+20] ; x - MOV EDI,[ESP+24] ; y - MOV EAX,[ESP+28] ; col - INT 0x40 - POP EBX - POP ESI - POP EDI - RET - -_api_refreshwin: ; void api_refreshwin(int win, int x0, int y0, int x1, int y1); - PUSH EDI - PUSH ESI - PUSH EBX - MOV EDX,12 - MOV EBX,[ESP+16] ; win - MOV EAX,[ESP+20] ; x0 - MOV ECX,[ESP+24] ; y0 - MOV ESI,[ESP+28] ; x1 - MOV EDI,[ESP+32] ; y1 - INT 0x40 - POP EBX - POP ESI - POP EDI - RET - -_api_linewin: ; void api_linewin(int win, int x0, int y0, int x1, int y1, int col); - PUSH EDI - PUSH ESI - PUSH EBP - PUSH EBX - MOV EDX,13 - MOV EBX,[ESP+20] ; win - MOV EAX,[ESP+24] ; x0 - MOV ECX,[ESP+28] ; y0 - MOV ESI,[ESP+32] ; x1 - MOV EDI,[ESP+36] ; y1 - MOV EBP,[ESP+40] ; col - INT 0x40 - POP EBX - POP EBP - POP ESI - POP EDI - RET - -_api_closewin: ; void api_closewin(int win); - PUSH EBX - MOV EDX,14 - MOV EBX,[ESP+8] ; win - INT 0x40 - POP EBX - RET - -_api_getkey: ; int api_getkey(int mode); - MOV EDX,15 - MOV EAX,[ESP+4] ; mode - INT 0x40 - RET - -_api_alloctimer: ; int api_alloctimer(void); - MOV EDX,16 - INT 0x40 - RET - -_api_inittimer: ; void api_inittimer(int timer, int data); - PUSH EBX - MOV EDX,17 - MOV EBX,[ESP+ 8] ; timer - MOV EAX,[ESP+12] ; data - INT 0x40 - POP EBX - RET - -_api_settimer: ; void api_settimer(int timer, int time); - PUSH EBX - MOV EDX,18 - MOV EBX,[ESP+ 8] ; timer - MOV EAX,[ESP+12] ; time - INT 0x40 - POP EBX - RET - -_api_freetimer: ; void api_freetimer(int timer); - PUSH EBX - MOV EDX,19 - MOV EBX,[ESP+ 8] ; timer - INT 0x40 - POP EBX - RET - -_api_beep: ; void api_beep(int tone); - MOV EDX,20 - MOV EAX,[ESP+4] ; tone - INT 0x40 - RET diff --git a/27_day/api001.nas b/27_day/api001.nas new file mode 100644 index 0000000..2f893a9 --- /dev/null +++ b/27_day/api001.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api001.nas"] + + GLOBAL _api_putchar + +[SECTION .text] + +_api_putchar: ; void api_putchar(int c); + MOV EDX,1 + MOV AL,[ESP+4] ; c + INT 0x40 + RET diff --git a/27_day/api002.nas b/27_day/api002.nas new file mode 100644 index 0000000..6ac9cc7 --- /dev/null +++ b/27_day/api002.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api002.nas"] + + GLOBAL _api_putstr0 + +[SECTION .text] + +_api_putstr0: ; void api_putstr0(char *s); + PUSH EBX + MOV EDX,2 + MOV EBX,[ESP+8] ; s + INT 0x40 + POP EBX + RET diff --git a/27_day/api003.nas b/27_day/api003.nas new file mode 100644 index 0000000..6c2d0fd --- /dev/null +++ b/27_day/api003.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api003.nas"] + + GLOBAL _api_putstr1 + +[SECTION .text] + +_api_putstr1: ; void api_putstr1(char *s, int l); + PUSH EBX + MOV EDX,3 + MOV EBX,[ESP+ 8] ; s + MOV ECX,[ESP+12] ; l + INT 0x40 + POP EBX + RET diff --git a/27_day/api004.nas b/27_day/api004.nas new file mode 100644 index 0000000..3c738a3 --- /dev/null +++ b/27_day/api004.nas @@ -0,0 +1,12 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api004.nas"] + + GLOBAL _api_end + +[SECTION .text] + +_api_end: ; void api_end(void); + MOV EDX,4 + INT 0x40 diff --git a/27_day/api005.nas b/27_day/api005.nas new file mode 100644 index 0000000..2157c61 --- /dev/null +++ b/27_day/api005.nas @@ -0,0 +1,24 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api005.nas"] + + GLOBAL _api_openwin + +[SECTION .text] + +_api_openwin: ; int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,5 + MOV EBX,[ESP+16] ; buf + MOV ESI,[ESP+20] ; xsiz + MOV EDI,[ESP+24] ; ysiz + MOV EAX,[ESP+28] ; col_inv + MOV ECX,[ESP+32] ; title + INT 0x40 + POP EBX + POP ESI + POP EDI + RET diff --git a/27_day/api006.nas b/27_day/api006.nas new file mode 100644 index 0000000..94cbb2d --- /dev/null +++ b/27_day/api006.nas @@ -0,0 +1,27 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api006.nas"] + + GLOBAL _api_putstrwin + +[SECTION .text] + +_api_putstrwin: ; void api_putstrwin(int win, int x, int y, int col, int len, char *str); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,6 + MOV EBX,[ESP+20] ; win + MOV ESI,[ESP+24] ; x + MOV EDI,[ESP+28] ; y + MOV EAX,[ESP+32] ; col + MOV ECX,[ESP+36] ; len + MOV EBP,[ESP+40] ; str + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET diff --git a/27_day/api007.nas b/27_day/api007.nas new file mode 100644 index 0000000..57be736 --- /dev/null +++ b/27_day/api007.nas @@ -0,0 +1,27 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api007.nas"] + + GLOBAL _api_boxfilwin + +[SECTION .text] + +_api_boxfilwin: ; void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,7 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET diff --git a/27_day/api008.nas b/27_day/api008.nas new file mode 100644 index 0000000..d1ed6c7 --- /dev/null +++ b/27_day/api008.nas @@ -0,0 +1,20 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api008.nas"] + + GLOBAL _api_initmalloc + +[SECTION .text] + +_api_initmalloc: ; void api_initmalloc(void); + PUSH EBX + MOV EDX,8 + MOV EBX,[CS:0x0020] ; malloc内存空间的地址 + MOV EAX,EBX + ADD EAX,32*1024 ; 加上32KB + MOV ECX,[CS:0x0000] ; 数据段的大小 + SUB ECX,EAX + INT 0x40 + POP EBX + RET diff --git a/27_day/api009.nas b/27_day/api009.nas new file mode 100644 index 0000000..bcd5307 --- /dev/null +++ b/27_day/api009.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api009.nas"] + + GLOBAL _api_malloc + +[SECTION .text] + +_api_malloc: ; char *api_malloc(int size); + PUSH EBX + MOV EDX,9 + MOV EBX,[CS:0x0020] + MOV ECX,[ESP+8] ; size + INT 0x40 + POP EBX + RET diff --git a/27_day/api010.nas b/27_day/api010.nas new file mode 100644 index 0000000..63a4ea5 --- /dev/null +++ b/27_day/api010.nas @@ -0,0 +1,18 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api010.nas"] + + GLOBAL _api_free + +[SECTION .text] + +_api_free: ; void api_free(char *addr, int size); + PUSH EBX + MOV EDX,10 + MOV EBX,[CS:0x0020] + MOV EAX,[ESP+ 8] ; addr + MOV ECX,[ESP+12] ; size + INT 0x40 + POP EBX + RET diff --git a/27_day/api011.nas b/27_day/api011.nas new file mode 100644 index 0000000..f5994b9 --- /dev/null +++ b/27_day/api011.nas @@ -0,0 +1,23 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api011.nas"] + + GLOBAL _api_point + +[SECTION .text] + +_api_point: ; void api_point(int win, int x, int y, int col); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,11 + MOV EBX,[ESP+16] ; win + MOV ESI,[ESP+20] ; x + MOV EDI,[ESP+24] ; y + MOV EAX,[ESP+28] ; col + INT 0x40 + POP EBX + POP ESI + POP EDI + RET diff --git a/27_day/api012.nas b/27_day/api012.nas new file mode 100644 index 0000000..9e9386f --- /dev/null +++ b/27_day/api012.nas @@ -0,0 +1,24 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api012.nas"] + + GLOBAL _api_refreshwin + +[SECTION .text] + +_api_refreshwin: ; void api_refreshwin(int win, int x0, int y0, int x1, int y1); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,12 + MOV EBX,[ESP+16] ; win + MOV EAX,[ESP+20] ; x0 + MOV ECX,[ESP+24] ; y0 + MOV ESI,[ESP+28] ; x1 + MOV EDI,[ESP+32] ; y1 + INT 0x40 + POP EBX + POP ESI + POP EDI + RET diff --git a/27_day/api013.nas b/27_day/api013.nas new file mode 100644 index 0000000..017f1ea --- /dev/null +++ b/27_day/api013.nas @@ -0,0 +1,27 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api013.nas"] + + GLOBAL _api_linewin + +[SECTION .text] + +_api_linewin: ; void api_linewin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,13 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET diff --git a/27_day/api014.nas b/27_day/api014.nas new file mode 100644 index 0000000..363db51 --- /dev/null +++ b/27_day/api014.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api014.nas"] + + GLOBAL _api_closewin + +[SECTION .text] + +_api_closewin: ; void api_closewin(int win); + PUSH EBX + MOV EDX,14 + MOV EBX,[ESP+8] ; win + INT 0x40 + POP EBX + RET diff --git a/27_day/api015.nas b/27_day/api015.nas new file mode 100644 index 0000000..bd27ec7 --- /dev/null +++ b/27_day/api015.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api015.nas"] + + GLOBAL _api_getkey + +[SECTION .text] + +_api_getkey: ; int api_getkey(int mode); + MOV EDX,15 + MOV EAX,[ESP+4] ; mode + INT 0x40 + RET diff --git a/27_day/api016.nas b/27_day/api016.nas new file mode 100644 index 0000000..e232412 --- /dev/null +++ b/27_day/api016.nas @@ -0,0 +1,13 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api016.nas"] + + GLOBAL _api_alloctimer + +[SECTION .text] + +_api_alloctimer: ; int api_alloctimer(void); + MOV EDX,16 + INT 0x40 + RET diff --git a/27_day/api017.nas b/27_day/api017.nas new file mode 100644 index 0000000..9e6a3cd --- /dev/null +++ b/27_day/api017.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api017.nas"] + + GLOBAL _api_inittimer + +[SECTION .text] + +_api_inittimer: ; void api_inittimer(int timer, int data); + PUSH EBX + MOV EDX,17 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; data + INT 0x40 + POP EBX + RET diff --git a/27_day/api018.nas b/27_day/api018.nas new file mode 100644 index 0000000..a91d6f1 --- /dev/null +++ b/27_day/api018.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api018.nas"] + + GLOBAL _api_settimer + +[SECTION .text] + +_api_settimer: ; void api_settimer(int timer, int time); + PUSH EBX + MOV EDX,18 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; time + INT 0x40 + POP EBX + RET diff --git a/27_day/api019.nas b/27_day/api019.nas new file mode 100644 index 0000000..d1c11e2 --- /dev/null +++ b/27_day/api019.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api019.nas"] + + GLOBAL _api_freetimer + +[SECTION .text] + +_api_freetimer: ; void api_freetimer(int timer); + PUSH EBX + MOV EDX,19 + MOV EBX,[ESP+ 8] ; timer + INT 0x40 + POP EBX + RET diff --git a/27_day/api020.nas b/27_day/api020.nas new file mode 100644 index 0000000..166bcda --- /dev/null +++ b/27_day/api020.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api020.nas"] + + GLOBAL _api_beep + +[SECTION .text] + +_api_beep: ; void api_beep(int tone); + MOV EDX,20 + MOV EAX,[ESP+4] ; tone + INT 0x40 + RET From a1129763ddcddd451c4d3d4dcaf8fd984586e375 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Tue, 17 May 2016 12:57:21 +0800 Subject: [PATCH 42/83] =?UTF-8?q?=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 27_day/Makefile | 95 +++++++++++++++++++++-------------------------- 27_day/a.c | 3 +- 27_day/apilib.h | 20 ++++++++++ 27_day/beepdown.c | 7 +--- 27_day/color.c | 8 +--- 27_day/color2.c | 10 +---- 27_day/crack7.nas | 28 -------------- 27_day/hello.nas | 16 -------- 27_day/hello2.nas | 9 ----- 27_day/hello3.c | 3 +- 27_day/hello4.c | 3 +- 27_day/lines.c | 9 +---- 27_day/noodle.c | 12 +----- 27_day/star1.c | 7 +--- 27_day/stars.c | 7 +--- 27_day/stars2.c | 8 +--- 27_day/walk.c | 11 +----- 27_day/winhelo.c | 3 +- 27_day/winhelo2.c | 5 +-- 27_day/winhelo3.c | 9 +---- 20 files changed, 79 insertions(+), 194 deletions(-) create mode 100644 27_day/apilib.h delete mode 100644 27_day/crack7.nas delete mode 100644 27_day/hello.nas delete mode 100644 27_day/hello2.nas diff --git a/27_day/Makefile b/27_day/Makefile index 719f71d..f1ed997 100644 --- a/27_day/Makefile +++ b/27_day/Makefile @@ -21,15 +21,16 @@ BIM2HRB = $(TOOLPATH)bim2hrb.exe RULEFILE = $(TOOLPATH)haribote/haribote.rul EDIMG = $(TOOLPATH)edimg.exe IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe COPY = copy DEL = del -# 默认动作 +# ftHg default : $(MAKE) img -# 镜像文件生成 +# t@CK ipl10.bin : ipl10.nas Makefile $(NASK) ipl10.nas ipl10.bin ipl10.lst @@ -54,27 +55,24 @@ bootpack.hrb : bootpack.bim Makefile haribote.sys : asmhead.bin bootpack.hrb Makefile copy /B asmhead.bin+bootpack.hrb haribote.sys -hello.hrb : hello.nas Makefile - $(NASK) hello.nas hello.hrb hello.lst +apilib.lib : Makefile $(OBJS_API) + $(GOLIB) $(OBJS_API) out:apilib.lib -hello2.hrb : hello2.nas Makefile - $(NASK) hello2.nas hello2.hrb hello2.lst - -a.bim : a.obj $(OBJS_API) Makefile - $(OBJ2BIM) @$(RULEFILE) out:a.bim map:a.map a.obj $(OBJS_API) +a.bim : a.obj apilib.lib Makefile + $(OBJ2BIM) @$(RULEFILE) out:a.bim map:a.map a.obj apilib.lib a.hrb : a.bim Makefile $(BIM2HRB) a.bim a.hrb 0 -hello3.bim : hello3.obj $(OBJS_API) Makefile - $(OBJ2BIM) @$(RULEFILE) out:hello3.bim map:hello3.map hello3.obj $(OBJS_API) +hello3.bim : hello3.obj apilib.lib Makefile + $(OBJ2BIM) @$(RULEFILE) out:hello3.bim map:hello3.map hello3.obj apilib.lib hello3.hrb : hello3.bim Makefile $(BIM2HRB) hello3.bim hello3.hrb 0 -hello4.bim : hello4.obj $(OBJS_API) Makefile +hello4.bim : hello4.obj apilib.lib Makefile $(OBJ2BIM) @$(RULEFILE) out:hello4.bim stack:1k map:hello4.map \ - hello4.obj $(OBJS_API) + hello4.obj apilib.lib hello4.hrb : hello4.bim Makefile $(BIM2HRB) hello4.bim hello4.hrb 0 @@ -85,108 +83,99 @@ hello5.bim : hello5.obj Makefile hello5.hrb : hello5.bim Makefile $(BIM2HRB) hello5.bim hello5.hrb 0 -winhelo.bim : winhelo.obj $(OBJS_API) Makefile +winhelo.bim : winhelo.obj apilib.lib Makefile $(OBJ2BIM) @$(RULEFILE) out:winhelo.bim stack:1k map:winhelo.map \ - winhelo.obj $(OBJS_API) + winhelo.obj apilib.lib winhelo.hrb : winhelo.bim Makefile $(BIM2HRB) winhelo.bim winhelo.hrb 0 -winhelo2.bim : winhelo2.obj $(OBJS_API) Makefile +winhelo2.bim : winhelo2.obj apilib.lib Makefile $(OBJ2BIM) @$(RULEFILE) out:winhelo2.bim stack:1k map:winhelo2.map \ - winhelo2.obj $(OBJS_API) + winhelo2.obj apilib.lib winhelo2.hrb : winhelo2.bim Makefile $(BIM2HRB) winhelo2.bim winhelo2.hrb 0 -winhelo3.bim : winhelo3.obj $(OBJS_API) Makefile +winhelo3.bim : winhelo3.obj apilib.lib Makefile $(OBJ2BIM) @$(RULEFILE) out:winhelo3.bim stack:1k map:winhelo3.map \ - winhelo3.obj $(OBJS_API) + winhelo3.obj apilib.lib winhelo3.hrb : winhelo3.bim Makefile $(BIM2HRB) winhelo3.bim winhelo3.hrb 40k -star1.bim : star1.obj $(OBJS_API) Makefile +star1.bim : star1.obj apilib.lib Makefile $(OBJ2BIM) @$(RULEFILE) out:star1.bim stack:1k map:star1.map \ - star1.obj $(OBJS_API) + star1.obj apilib.lib star1.hrb : star1.bim Makefile $(BIM2HRB) star1.bim star1.hrb 47k -stars.bim : stars.obj $(OBJS_API) Makefile +stars.bim : stars.obj apilib.lib Makefile $(OBJ2BIM) @$(RULEFILE) out:stars.bim stack:1k map:stars.map \ - stars.obj $(OBJS_API) + stars.obj apilib.lib stars.hrb : stars.bim Makefile $(BIM2HRB) stars.bim stars.hrb 47k -stars2.bim : stars2.obj $(OBJS_API) Makefile +stars2.bim : stars2.obj apilib.lib Makefile $(OBJ2BIM) @$(RULEFILE) out:stars2.bim stack:1k map:stars2.map \ - stars2.obj $(OBJS_API) + stars2.obj apilib.lib stars2.hrb : stars2.bim Makefile $(BIM2HRB) stars2.bim stars2.hrb 47k -lines.bim : lines.obj $(OBJS_API) Makefile +lines.bim : lines.obj apilib.lib Makefile $(OBJ2BIM) @$(RULEFILE) out:lines.bim stack:1k map:lines.map \ - lines.obj $(OBJS_API) + lines.obj apilib.lib lines.hrb : lines.bim Makefile $(BIM2HRB) lines.bim lines.hrb 48k -walk.bim : walk.obj $(OBJS_API) Makefile +walk.bim : walk.obj apilib.lib Makefile $(OBJ2BIM) @$(RULEFILE) out:walk.bim stack:1k map:walk.map \ - walk.obj $(OBJS_API) + walk.obj apilib.lib walk.hrb : walk.bim Makefile $(BIM2HRB) walk.bim walk.hrb 48k -noodle.bim : noodle.obj $(OBJS_API) Makefile +noodle.bim : noodle.obj apilib.lib Makefile $(OBJ2BIM) @$(RULEFILE) out:noodle.bim stack:1k map:noodle.map \ - noodle.obj $(OBJS_API) + noodle.obj apilib.lib noodle.hrb : noodle.bim Makefile $(BIM2HRB) noodle.bim noodle.hrb 40k -beepdown.bim : beepdown.obj $(OBJS_API) Makefile +beepdown.bim : beepdown.obj apilib.lib Makefile $(OBJ2BIM) @$(RULEFILE) out:beepdown.bim stack:1k map:beepdown.map \ - beepdown.obj $(OBJS_API) + beepdown.obj apilib.lib beepdown.hrb : beepdown.bim Makefile $(BIM2HRB) beepdown.bim beepdown.hrb 40k -color.bim : color.obj $(OBJS_API) Makefile +color.bim : color.obj apilib.lib Makefile $(OBJ2BIM) @$(RULEFILE) out:color.bim stack:1k map:color.map \ - color.obj $(OBJS_API) + color.obj apilib.lib color.hrb : color.bim Makefile $(BIM2HRB) color.bim color.hrb 56k -color2.bim : color2.obj $(OBJS_API) Makefile +color2.bim : color2.obj apilib.lib Makefile $(OBJ2BIM) @$(RULEFILE) out:color2.bim stack:1k map:color2.map \ - color2.obj $(OBJS_API) + color2.obj apilib.lib color2.hrb : color2.bim Makefile $(BIM2HRB) color2.bim color2.hrb 56k -crack7.bim : crack7.obj Makefile - $(OBJ2BIM) @$(RULEFILE) out:crack7.bim stack:1k map:crack7.map crack7.obj - -crack7.hrb : crack7.bim Makefile - $(BIM2HRB) crack7.bim crack7.hrb 0k - haribote.img : ipl10.bin haribote.sys Makefile \ - hello.hrb hello2.hrb a.hrb hello3.hrb hello4.hrb hello5.hrb \ - winhelo.hrb winhelo2.hrb winhelo3.hrb star1.hrb stars.hrb stars2.hrb \ - lines.hrb walk.hrb noodle.hrb beepdown.hrb color.hrb color2.hrb \ - crack7.hrb + a.hrb hello3.hrb hello4.hrb hello5.hrb winhelo.hrb winhelo2.hrb \ + winhelo3.hrb star1.hrb stars.hrb stars2.hrb lines.hrb walk.hrb \ + noodle.hrb beepdown.hrb color.hrb color2.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:ipl10.bin len:512 from:0 to:0 \ copy from:haribote.sys to:@: \ copy from:ipl10.nas to:@: \ copy from:make.bat to:@: \ - copy from:hello.hrb to:@: \ - copy from:hello2.hrb to:@: \ copy from:a.hrb to:@: \ copy from:hello3.hrb to:@: \ copy from:hello4.hrb to:@: \ @@ -203,12 +192,11 @@ haribote.img : ipl10.bin haribote.sys Makefile \ copy from:beepdown.hrb to:@: \ copy from:color.hrb to:@: \ copy from:color2.hrb to:@: \ - copy from:crack7.hrb to:@: \ imgout:haribote.img -# 其他指令 +# ʋK -%.gas : %.c bootpack.h Makefile +%.gas : %.c bootpack.h apilib.h Makefile $(CC1) -o $*.gas $*.c %.nas : %.gas Makefile @@ -217,7 +205,7 @@ haribote.img : ipl10.bin haribote.sys Makefile \ %.obj : %.nas Makefile $(NASK) $*.nas $*.obj $*.lst -# 运行程序 +# R}h img : $(MAKE) haribote.img @@ -239,6 +227,7 @@ clean : -$(DEL) *.bim -$(DEL) *.hrb -$(DEL) haribote.sys + -$(DEL) apilib.lib src_only : $(MAKE) clean diff --git a/27_day/a.c b/27_day/a.c index a6668af..3df81f5 100644 --- a/27_day/a.c +++ b/27_day/a.c @@ -1,5 +1,4 @@ -void api_putchar(int c); -void api_end(void); +#include "apilib.h" void HariMain(void) { diff --git a/27_day/apilib.h b/27_day/apilib.h new file mode 100644 index 0000000..80ec6e0 --- /dev/null +++ b/27_day/apilib.h @@ -0,0 +1,20 @@ +void api_putchar(int c); +void api_putstr0(char *s); +void api_putstr1(char *s, int l); +void api_end(void); +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_free(char *addr, int size); +void api_point(int win, int x, int y, int col); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +void api_closewin(int win); +int api_getkey(int mode); +int api_alloctimer(void); +void api_inittimer(int timer, int data); +void api_settimer(int timer, int time); +void api_freetimer(int timer); +void api_beep(int tone); diff --git a/27_day/beepdown.c b/27_day/beepdown.c index db1aa59..d08962c 100644 --- a/27_day/beepdown.c +++ b/27_day/beepdown.c @@ -1,9 +1,4 @@ -void api_end(void); -int api_getkey(int mode); -int api_alloctimer(void); -void api_inittimer(int timer, int data); -void api_settimer(int timer, int time); -void api_beep(int tone); +#include "apilib.h" void HariMain(void) { diff --git a/27_day/color.c b/27_day/color.c index c004c14..ce228e2 100644 --- a/27_day/color.c +++ b/27_day/color.c @@ -1,10 +1,4 @@ -int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); -void api_initmalloc(void); -char *api_malloc(int size); -void api_refreshwin(int win, int x0, int y0, int x1, int y1); -void api_linewin(int win, int x0, int y0, int x1, int y1, int col); -int api_getkey(int mode); -void api_end(void); +#include "apilib.h" void HariMain(void) { diff --git a/27_day/color2.c b/27_day/color2.c index c063768..82e3f6a 100644 --- a/27_day/color2.c +++ b/27_day/color2.c @@ -1,10 +1,4 @@ -int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); -void api_initmalloc(void); -char *api_malloc(int size); -void api_refreshwin(int win, int x0, int y0, int x1, int y1); -void api_linewin(int win, int x0, int y0, int x1, int y1, int col); -int api_getkey(int mode); -void api_end(void); +#include "apilib.h" unsigned char rgb2pal(int r, int g, int b, int x, int y); @@ -21,7 +15,7 @@ void HariMain(void) } } api_refreshwin(win, 8, 28, 136, 156); - api_getkey(1); /*等待按下任意键*/ + api_getkey(1); /* �Ă��Ƃ��ȃL�[���͂�҂� */ api_end(); } diff --git a/27_day/crack7.nas b/27_day/crack7.nas deleted file mode 100644 index 134090f..0000000 --- a/27_day/crack7.nas +++ /dev/null @@ -1,28 +0,0 @@ -[FORMAT "WCOFF"] -[INSTRSET "i486p"] -[BITS 32] -[FILE "crack7.nas"] - - GLOBAL _HariMain - -[SECTION .text] - -_HariMain: - MOV AX,1005*8 - MOV DS,AX - CMP DWORD [DS:0x0004],'Hari' - JNE fin ; 不是应用程序,因此不执行任何操作 - - MOV ECX,[DS:0x0000] ; 读取该应用程序数据段的大小 - MOV AX,2005*8 - MOV DS,AX - -crackloop: ; 整个用123填充 - ADD ECX,-1 - MOV BYTE [DS:ECX],123 - CMP ECX,0 - JNE crackloop - -fin: ; 结束 - MOV EDX,4 - INT 0x40 diff --git a/27_day/hello.nas b/27_day/hello.nas deleted file mode 100644 index b4e9576..0000000 --- a/27_day/hello.nas +++ /dev/null @@ -1,16 +0,0 @@ -[INSTRSET "i486p"] -[BITS 32] - MOV ECX,msg - MOV EDX,1 -putloop: - MOV AL,[CS:ECX] - CMP AL,0 - JE fin - INT 0x40 - ADD ECX,1 - JMP putloop -fin: - MOV EDX,4 - INT 0x40 -msg: - DB "hello",0 diff --git a/27_day/hello2.nas b/27_day/hello2.nas deleted file mode 100644 index 5e1e58c..0000000 --- a/27_day/hello2.nas +++ /dev/null @@ -1,9 +0,0 @@ -[INSTRSET "i486p"] -[BITS 32] - MOV EDX,2 - MOV EBX,msg - INT 0x40 - MOV EDX,4 - INT 0x40 -msg: - DB "hello",0 diff --git a/27_day/hello3.c b/27_day/hello3.c index 97d3236..f71cedf 100644 --- a/27_day/hello3.c +++ b/27_day/hello3.c @@ -1,5 +1,4 @@ -void api_putchar(int c); -void api_end(void); +#include "apilib.h" void HariMain(void) { diff --git a/27_day/hello4.c b/27_day/hello4.c index 7fb73de..ec04384 100644 --- a/27_day/hello4.c +++ b/27_day/hello4.c @@ -1,5 +1,4 @@ -void api_putstr0(char *s); -void api_end(void); +#include "apilib.h" void HariMain(void) { diff --git a/27_day/lines.c b/27_day/lines.c index 83e7ceb..5217faa 100644 --- a/27_day/lines.c +++ b/27_day/lines.c @@ -1,11 +1,4 @@ -int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); -void api_initmalloc(void); -char *api_malloc(int size); -void api_refreshwin(int win, int x0, int y0, int x1, int y1); -void api_linewin(int win, int x0, int y0, int x1, int y1, int col); -void api_closewin(int win); -int api_getkey(int mode); -void api_end(void); +#include "apilib.h" void HariMain(void) { diff --git a/27_day/noodle.c b/27_day/noodle.c index 13b9033..108d148 100644 --- a/27_day/noodle.c +++ b/27_day/noodle.c @@ -1,15 +1,5 @@ #include - -int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); -void api_putstrwin(int win, int x, int y, int col, int len, char *str); -void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); -void api_initmalloc(void); -char *api_malloc(int size); -int api_getkey(int mode); -int api_alloctimer(void); -void api_inittimer(int timer, int data); -void api_settimer(int timer, int time); -void api_end(void); +#include "apilib.h" void HariMain(void) { diff --git a/27_day/star1.c b/27_day/star1.c index 8d80ffa..6477c2a 100644 --- a/27_day/star1.c +++ b/27_day/star1.c @@ -1,9 +1,4 @@ -int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); -void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); -void api_initmalloc(void); -char *api_malloc(int size); -void api_point(int win, int x, int y, int col); -void api_end(void); +#include "apilib.h" void HariMain(void) { diff --git a/27_day/stars.c b/27_day/stars.c index dc38b2b..c8dae64 100644 --- a/27_day/stars.c +++ b/27_day/stars.c @@ -1,9 +1,4 @@ -int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); -void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); -void api_initmalloc(void); -char *api_malloc(int size); -void api_point(int win, int x, int y, int col); -void api_end(void); +#include "apilib.h" int rand(void); /*产生0~32767之间的随机数*/ diff --git a/27_day/stars2.c b/27_day/stars2.c index 94a029e..11ec0e1 100644 --- a/27_day/stars2.c +++ b/27_day/stars2.c @@ -1,10 +1,4 @@ -int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); -void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); -void api_initmalloc(void); -char *api_malloc(int size); -void api_point(int win, int x, int y, int col); -void api_refreshwin(int win, int x0, int y0, int x1, int y1); -void api_end(void); +#include "apilib.h" int rand(void); /*产生0~32767的随机数*/ diff --git a/27_day/walk.c b/27_day/walk.c index 6b106b4..4772f8a 100644 --- a/27_day/walk.c +++ b/27_day/walk.c @@ -1,13 +1,4 @@ -int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); -void api_putstrwin(int win, int x, int y, int col, int len, char *str); -void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); -void api_initmalloc(void); -char *api_malloc(int size); -void api_refreshwin(int win, int x0, int y0, int x1, int y1); -void api_linewin(int win, int x0, int y0, int x1, int y1, int col); -void api_closewin(int win); -int api_getkey(int mode); -void api_end(void); +#include "apilib.h" void HariMain(void) { diff --git a/27_day/winhelo.c b/27_day/winhelo.c index 6d7fb0a..a56225a 100644 --- a/27_day/winhelo.c +++ b/27_day/winhelo.c @@ -1,5 +1,4 @@ -int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); -void api_end(void); +#include "apilib.h" char buf[150 * 50]; diff --git a/27_day/winhelo2.c b/27_day/winhelo2.c index f00b007..3cf30c6 100644 --- a/27_day/winhelo2.c +++ b/27_day/winhelo2.c @@ -1,7 +1,4 @@ -int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); -void api_putstrwin(int win, int x, int y, int col, int len, char *str); -void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); -void api_end(void); +#include "apilib.h" char buf[150 * 50]; diff --git a/27_day/winhelo3.c b/27_day/winhelo3.c index 527ec01..3eafc35 100644 --- a/27_day/winhelo3.c +++ b/27_day/winhelo3.c @@ -1,9 +1,4 @@ -int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); -void api_putstrwin(int win, int x, int y, int col, int len, char *str); -void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); -void api_initmalloc(void); -char *api_malloc(int size); -void api_end(void); +#include "apilib.h" void HariMain(void) { @@ -16,4 +11,4 @@ void HariMain(void) api_boxfilwin(win, 8, 36, 141, 43, 6); /*浅蓝色*/ api_putstrwin(win, 28, 28, 0 , 12, "hello, world");/*黑色*/ api_end(); -} \ No newline at end of file +} From f025b0083fcd1aed1b1742fb6d3dbc9fb657a5c6 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Tue, 17 May 2016 13:30:27 +0800 Subject: [PATCH 43/83] =?UTF-8?q?=E6=95=B4=E7=90=86make=E7=8E=AF=E5=A2=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 27_day/Makefile | 312 ++++++++++------------------- 27_day/a/!cons_9x.bat | 1 + 27_day/a/!cons_nt.bat | 1 + 27_day/a/Makefile | 5 + 27_day/{ => a}/a.c | 0 27_day/a/make.bat | 1 + 27_day/apilib/!cons_9x.bat | 1 + 27_day/apilib/!cons_nt.bat | 1 + 27_day/apilib/Makefile | 47 +++++ 27_day/{ => apilib}/api001.nas | 0 27_day/{ => apilib}/api002.nas | 0 27_day/{ => apilib}/api003.nas | 0 27_day/{ => apilib}/api004.nas | 0 27_day/{ => apilib}/api005.nas | 0 27_day/{ => apilib}/api006.nas | 0 27_day/{ => apilib}/api007.nas | 0 27_day/{ => apilib}/api008.nas | 0 27_day/{ => apilib}/api009.nas | 0 27_day/{ => apilib}/api010.nas | 0 27_day/{ => apilib}/api011.nas | 0 27_day/{ => apilib}/api012.nas | 0 27_day/{ => apilib}/api013.nas | 0 27_day/{ => apilib}/api014.nas | 0 27_day/{ => apilib}/api015.nas | 0 27_day/{ => apilib}/api016.nas | 0 27_day/{ => apilib}/api017.nas | 0 27_day/{ => apilib}/api018.nas | 0 27_day/{ => apilib}/api019.nas | 0 27_day/{ => apilib}/api020.nas | 0 27_day/apilib/apilib.lib | Bin 0 -> 8966 bytes 27_day/apilib/make.bat | 1 + 27_day/app_make.txt | 79 ++++++++ 27_day/beepdown/!cons_9x.bat | 1 + 27_day/beepdown/!cons_nt.bat | 1 + 27_day/beepdown/Makefile | 5 + 27_day/{ => beepdown}/beepdown.c | 0 27_day/beepdown/make.bat | 1 + 27_day/color/!cons_9x.bat | 1 + 27_day/color/!cons_nt.bat | 1 + 27_day/color/Makefile | 5 + 27_day/{ => color}/color.c | 0 27_day/color/make.bat | 1 + 27_day/color2/!cons_9x.bat | 1 + 27_day/color2/!cons_nt.bat | 1 + 27_day/color2/Makefile | 5 + 27_day/{ => color2}/color2.c | 0 27_day/color2/make.bat | 1 + 27_day/haribote.rul | 10 + 27_day/haribote/!cons_9x.bat | 1 + 27_day/haribote/!cons_nt.bat | 1 + 27_day/haribote/Makefile | 79 ++++++++ 27_day/{ => haribote}/asmhead.nas | 0 27_day/{ => haribote}/bootpack.c | 0 27_day/{ => haribote}/bootpack.h | 0 27_day/{ => haribote}/console.c | 0 27_day/{ => haribote}/dsctbl.c | 0 27_day/{ => haribote}/fifo.c | 0 27_day/{ => haribote}/file.c | 0 27_day/{ => haribote}/graphic.c | 0 27_day/{ => haribote}/hankaku.txt | 0 27_day/haribote/haribote.sys | Bin 0 -> 33331 bytes 27_day/{ => haribote}/int.c | 0 27_day/haribote/ipl10.bin | Bin 0 -> 512 bytes 27_day/{ => haribote}/ipl10.nas | 0 27_day/{ => haribote}/keyboard.c | 0 27_day/haribote/make.bat | 1 + 27_day/{ => haribote}/memory.c | 0 27_day/{ => haribote}/mouse.c | 0 27_day/{ => haribote}/mtask.c | 0 27_day/{ => haribote}/naskfunc.nas | 0 27_day/{ => haribote}/sheet.c | 0 27_day/{ => haribote}/timer.c | 0 27_day/{ => haribote}/window.c | 0 27_day/hello3/!cons_9x.bat | 1 + 27_day/hello3/!cons_nt.bat | 1 + 27_day/hello3/Makefile | 5 + 27_day/{ => hello3}/hello3.c | 0 27_day/hello3/make.bat | 1 + 27_day/hello4/!cons_9x.bat | 1 + 27_day/hello4/!cons_nt.bat | 1 + 27_day/hello4/Makefile | 5 + 27_day/{ => hello4}/hello4.c | 0 27_day/hello4/make.bat | 1 + 27_day/hello5/!cons_9x.bat | 1 + 27_day/hello5/!cons_nt.bat | 1 + 27_day/hello5/Makefile | 5 + 27_day/{ => hello5}/hello5.nas | 0 27_day/hello5/make.bat | 1 + 27_day/lines/!cons_9x.bat | 1 + 27_day/lines/!cons_nt.bat | 1 + 27_day/lines/Makefile | 5 + 27_day/{ => lines}/lines.c | 0 27_day/lines/make.bat | 1 + 27_day/noodle/!cons_9x.bat | 1 + 27_day/noodle/!cons_nt.bat | 1 + 27_day/noodle/Makefile | 5 + 27_day/noodle/make.bat | 1 + 27_day/{ => noodle}/noodle.c | 0 27_day/star1/!cons_9x.bat | 1 + 27_day/star1/!cons_nt.bat | 1 + 27_day/star1/Makefile | 5 + 27_day/star1/make.bat | 1 + 27_day/{ => star1}/star1.c | 5 + 27_day/stars/!cons_9x.bat | 1 + 27_day/stars/!cons_nt.bat | 1 + 27_day/stars/Makefile | 5 + 27_day/stars/make.bat | 1 + 27_day/{ => stars}/stars.c | 5 + 27_day/stars2/!cons_9x.bat | 1 + 27_day/stars2/!cons_nt.bat | 1 + 27_day/stars2/Makefile | 5 + 27_day/stars2/make.bat | 1 + 27_day/{ => stars2}/stars2.c | 5 + 27_day/walk/!cons_9x.bat | 1 + 27_day/walk/!cons_nt.bat | 1 + 27_day/walk/Makefile | 5 + 27_day/walk/make.bat | 1 + 27_day/{ => walk}/walk.c | 0 27_day/winhelo/!cons_9x.bat | 1 + 27_day/winhelo/!cons_nt.bat | 1 + 27_day/winhelo/Makefile | 5 + 27_day/winhelo/make.bat | 1 + 27_day/{ => winhelo}/winhelo.c | 5 + 27_day/winhelo2/!cons_9x.bat | 1 + 27_day/winhelo2/!cons_nt.bat | 1 + 27_day/winhelo2/Makefile | 5 + 27_day/winhelo2/make.bat | 1 + 27_day/{ => winhelo2}/winhelo2.c | 5 + 27_day/winhelo3/!cons_9x.bat | 1 + 27_day/winhelo3/!cons_nt.bat | 1 + 27_day/winhelo3/Makefile | 5 + 27_day/winhelo3/make.bat | 1 + 27_day/{ => winhelo3}/winhelo3.c | 5 + 134 files changed, 490 insertions(+), 202 deletions(-) create mode 100644 .gitignore create mode 100644 27_day/a/!cons_9x.bat create mode 100644 27_day/a/!cons_nt.bat create mode 100644 27_day/a/Makefile rename 27_day/{ => a}/a.c (100%) create mode 100644 27_day/a/make.bat create mode 100644 27_day/apilib/!cons_9x.bat create mode 100644 27_day/apilib/!cons_nt.bat create mode 100644 27_day/apilib/Makefile rename 27_day/{ => apilib}/api001.nas (100%) rename 27_day/{ => apilib}/api002.nas (100%) rename 27_day/{ => apilib}/api003.nas (100%) rename 27_day/{ => apilib}/api004.nas (100%) rename 27_day/{ => apilib}/api005.nas (100%) rename 27_day/{ => apilib}/api006.nas (100%) rename 27_day/{ => apilib}/api007.nas (100%) rename 27_day/{ => apilib}/api008.nas (100%) rename 27_day/{ => apilib}/api009.nas (100%) rename 27_day/{ => apilib}/api010.nas (100%) rename 27_day/{ => apilib}/api011.nas (100%) rename 27_day/{ => apilib}/api012.nas (100%) rename 27_day/{ => apilib}/api013.nas (100%) rename 27_day/{ => apilib}/api014.nas (100%) rename 27_day/{ => apilib}/api015.nas (100%) rename 27_day/{ => apilib}/api016.nas (100%) rename 27_day/{ => apilib}/api017.nas (100%) rename 27_day/{ => apilib}/api018.nas (100%) rename 27_day/{ => apilib}/api019.nas (100%) rename 27_day/{ => apilib}/api020.nas (100%) create mode 100644 27_day/apilib/apilib.lib create mode 100644 27_day/apilib/make.bat create mode 100644 27_day/app_make.txt create mode 100644 27_day/beepdown/!cons_9x.bat create mode 100644 27_day/beepdown/!cons_nt.bat create mode 100644 27_day/beepdown/Makefile rename 27_day/{ => beepdown}/beepdown.c (100%) create mode 100644 27_day/beepdown/make.bat create mode 100644 27_day/color/!cons_9x.bat create mode 100644 27_day/color/!cons_nt.bat create mode 100644 27_day/color/Makefile rename 27_day/{ => color}/color.c (100%) create mode 100644 27_day/color/make.bat create mode 100644 27_day/color2/!cons_9x.bat create mode 100644 27_day/color2/!cons_nt.bat create mode 100644 27_day/color2/Makefile rename 27_day/{ => color2}/color2.c (100%) create mode 100644 27_day/color2/make.bat create mode 100644 27_day/haribote.rul create mode 100644 27_day/haribote/!cons_9x.bat create mode 100644 27_day/haribote/!cons_nt.bat create mode 100644 27_day/haribote/Makefile rename 27_day/{ => haribote}/asmhead.nas (100%) rename 27_day/{ => haribote}/bootpack.c (100%) rename 27_day/{ => haribote}/bootpack.h (100%) rename 27_day/{ => haribote}/console.c (100%) rename 27_day/{ => haribote}/dsctbl.c (100%) rename 27_day/{ => haribote}/fifo.c (100%) rename 27_day/{ => haribote}/file.c (100%) rename 27_day/{ => haribote}/graphic.c (100%) rename 27_day/{ => haribote}/hankaku.txt (100%) create mode 100644 27_day/haribote/haribote.sys rename 27_day/{ => haribote}/int.c (100%) create mode 100644 27_day/haribote/ipl10.bin rename 27_day/{ => haribote}/ipl10.nas (100%) rename 27_day/{ => haribote}/keyboard.c (100%) create mode 100644 27_day/haribote/make.bat rename 27_day/{ => haribote}/memory.c (100%) rename 27_day/{ => haribote}/mouse.c (100%) rename 27_day/{ => haribote}/mtask.c (100%) rename 27_day/{ => haribote}/naskfunc.nas (100%) rename 27_day/{ => haribote}/sheet.c (100%) rename 27_day/{ => haribote}/timer.c (100%) rename 27_day/{ => haribote}/window.c (100%) create mode 100644 27_day/hello3/!cons_9x.bat create mode 100644 27_day/hello3/!cons_nt.bat create mode 100644 27_day/hello3/Makefile rename 27_day/{ => hello3}/hello3.c (100%) create mode 100644 27_day/hello3/make.bat create mode 100644 27_day/hello4/!cons_9x.bat create mode 100644 27_day/hello4/!cons_nt.bat create mode 100644 27_day/hello4/Makefile rename 27_day/{ => hello4}/hello4.c (100%) create mode 100644 27_day/hello4/make.bat create mode 100644 27_day/hello5/!cons_9x.bat create mode 100644 27_day/hello5/!cons_nt.bat create mode 100644 27_day/hello5/Makefile rename 27_day/{ => hello5}/hello5.nas (100%) create mode 100644 27_day/hello5/make.bat create mode 100644 27_day/lines/!cons_9x.bat create mode 100644 27_day/lines/!cons_nt.bat create mode 100644 27_day/lines/Makefile rename 27_day/{ => lines}/lines.c (100%) create mode 100644 27_day/lines/make.bat create mode 100644 27_day/noodle/!cons_9x.bat create mode 100644 27_day/noodle/!cons_nt.bat create mode 100644 27_day/noodle/Makefile create mode 100644 27_day/noodle/make.bat rename 27_day/{ => noodle}/noodle.c (100%) create mode 100644 27_day/star1/!cons_9x.bat create mode 100644 27_day/star1/!cons_nt.bat create mode 100644 27_day/star1/Makefile create mode 100644 27_day/star1/make.bat rename 27_day/{ => star1}/star1.c (74%) create mode 100644 27_day/stars/!cons_9x.bat create mode 100644 27_day/stars/!cons_nt.bat create mode 100644 27_day/stars/Makefile create mode 100644 27_day/stars/make.bat rename 27_day/{ => stars}/stars.c (82%) create mode 100644 27_day/stars2/!cons_9x.bat create mode 100644 27_day/stars2/!cons_nt.bat create mode 100644 27_day/stars2/Makefile create mode 100644 27_day/stars2/make.bat rename 27_day/{ => stars2}/stars2.c (83%) create mode 100644 27_day/walk/!cons_9x.bat create mode 100644 27_day/walk/!cons_nt.bat create mode 100644 27_day/walk/Makefile create mode 100644 27_day/walk/make.bat rename 27_day/{ => walk}/walk.c (100%) create mode 100644 27_day/winhelo/!cons_9x.bat create mode 100644 27_day/winhelo/!cons_nt.bat create mode 100644 27_day/winhelo/Makefile create mode 100644 27_day/winhelo/make.bat rename 27_day/{ => winhelo}/winhelo.c (60%) create mode 100644 27_day/winhelo2/!cons_9x.bat create mode 100644 27_day/winhelo2/!cons_nt.bat create mode 100644 27_day/winhelo2/Makefile create mode 100644 27_day/winhelo2/make.bat rename 27_day/{ => winhelo2}/winhelo2.c (73%) create mode 100644 27_day/winhelo3/!cons_9x.bat create mode 100644 27_day/winhelo3/!cons_nt.bat create mode 100644 27_day/winhelo3/Makefile create mode 100644 27_day/winhelo3/make.bat rename 27_day/{ => winhelo3}/winhelo3.c (76%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8444cec --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.hrb diff --git a/27_day/Makefile b/27_day/Makefile index f1ed997..23e155c 100644 --- a/27_day/Makefile +++ b/27_day/Makefile @@ -1,234 +1,142 @@ -OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \ - int.obj fifo.obj keyboard.obj mouse.obj memory.obj sheet.obj timer.obj \ - mtask.obj window.obj console.obj file.obj - -OBJS_API = api001.obj api002.obj api003.obj api004.obj api005.obj api006.obj \ - api007.obj api008.obj api009.obj api010.obj api011.obj api012.obj \ - api013.obj api014.obj api015.obj api016.obj api017.obj api018.obj \ - api019.obj api020.obj - TOOLPATH = ../z_tools/ INCPATH = ../z_tools/haribote/ MAKE = $(TOOLPATH)make.exe -r -NASK = $(TOOLPATH)nask.exe -CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet -GAS2NASK = $(TOOLPATH)gas2nask.exe -a -OBJ2BIM = $(TOOLPATH)obj2bim.exe -MAKEFONT = $(TOOLPATH)makefont.exe -BIN2OBJ = $(TOOLPATH)bin2obj.exe -BIM2HRB = $(TOOLPATH)bim2hrb.exe -RULEFILE = $(TOOLPATH)haribote/haribote.rul EDIMG = $(TOOLPATH)edimg.exe IMGTOL = $(TOOLPATH)imgtol.com -GOLIB = $(TOOLPATH)golib00.exe COPY = copy DEL = del -# ftHg +#默认动作 default : - $(MAKE) img - -# t@CK - -ipl10.bin : ipl10.nas Makefile - $(NASK) ipl10.nas ipl10.bin ipl10.lst - -asmhead.bin : asmhead.nas Makefile - $(NASK) asmhead.nas asmhead.bin asmhead.lst - -hankaku.bin : hankaku.txt Makefile - $(MAKEFONT) hankaku.txt hankaku.bin - -hankaku.obj : hankaku.bin Makefile - $(BIN2OBJ) hankaku.bin hankaku.obj _hankaku - -bootpack.bim : $(OBJS_BOOTPACK) Makefile - $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \ - $(OBJS_BOOTPACK) -# 3MB+64KB=3136KB - -bootpack.hrb : bootpack.bim Makefile - $(BIM2HRB) bootpack.bim bootpack.hrb 0 - -haribote.sys : asmhead.bin bootpack.hrb Makefile - copy /B asmhead.bin+bootpack.hrb haribote.sys - -apilib.lib : Makefile $(OBJS_API) - $(GOLIB) $(OBJS_API) out:apilib.lib - -a.bim : a.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:a.bim map:a.map a.obj apilib.lib - -a.hrb : a.bim Makefile - $(BIM2HRB) a.bim a.hrb 0 - -hello3.bim : hello3.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:hello3.bim map:hello3.map hello3.obj apilib.lib - -hello3.hrb : hello3.bim Makefile - $(BIM2HRB) hello3.bim hello3.hrb 0 - -hello4.bim : hello4.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:hello4.bim stack:1k map:hello4.map \ - hello4.obj apilib.lib - -hello4.hrb : hello4.bim Makefile - $(BIM2HRB) hello4.bim hello4.hrb 0 - -hello5.bim : hello5.obj Makefile - $(OBJ2BIM) @$(RULEFILE) out:hello5.bim stack:1k map:hello5.map hello5.obj - -hello5.hrb : hello5.bim Makefile - $(BIM2HRB) hello5.bim hello5.hrb 0 - -winhelo.bim : winhelo.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:winhelo.bim stack:1k map:winhelo.map \ - winhelo.obj apilib.lib - -winhelo.hrb : winhelo.bim Makefile - $(BIM2HRB) winhelo.bim winhelo.hrb 0 - -winhelo2.bim : winhelo2.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:winhelo2.bim stack:1k map:winhelo2.map \ - winhelo2.obj apilib.lib - -winhelo2.hrb : winhelo2.bim Makefile - $(BIM2HRB) winhelo2.bim winhelo2.hrb 0 - -winhelo3.bim : winhelo3.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:winhelo3.bim stack:1k map:winhelo3.map \ - winhelo3.obj apilib.lib - -winhelo3.hrb : winhelo3.bim Makefile - $(BIM2HRB) winhelo3.bim winhelo3.hrb 40k - -star1.bim : star1.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:star1.bim stack:1k map:star1.map \ - star1.obj apilib.lib - -star1.hrb : star1.bim Makefile - $(BIM2HRB) star1.bim star1.hrb 47k - -stars.bim : stars.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:stars.bim stack:1k map:stars.map \ - stars.obj apilib.lib - -stars.hrb : stars.bim Makefile - $(BIM2HRB) stars.bim stars.hrb 47k - -stars2.bim : stars2.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:stars2.bim stack:1k map:stars2.map \ - stars2.obj apilib.lib - -stars2.hrb : stars2.bim Makefile - $(BIM2HRB) stars2.bim stars2.hrb 47k - -lines.bim : lines.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:lines.bim stack:1k map:lines.map \ - lines.obj apilib.lib - -lines.hrb : lines.bim Makefile - $(BIM2HRB) lines.bim lines.hrb 48k - -walk.bim : walk.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:walk.bim stack:1k map:walk.map \ - walk.obj apilib.lib - -walk.hrb : walk.bim Makefile - $(BIM2HRB) walk.bim walk.hrb 48k - -noodle.bim : noodle.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:noodle.bim stack:1k map:noodle.map \ - noodle.obj apilib.lib - -noodle.hrb : noodle.bim Makefile - $(BIM2HRB) noodle.bim noodle.hrb 40k - -beepdown.bim : beepdown.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:beepdown.bim stack:1k map:beepdown.map \ - beepdown.obj apilib.lib - -beepdown.hrb : beepdown.bim Makefile - $(BIM2HRB) beepdown.bim beepdown.hrb 40k - -color.bim : color.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:color.bim stack:1k map:color.map \ - color.obj apilib.lib - -color.hrb : color.bim Makefile - $(BIM2HRB) color.bim color.hrb 56k - -color2.bim : color2.obj apilib.lib Makefile - $(OBJ2BIM) @$(RULEFILE) out:color2.bim stack:1k map:color2.map \ - color2.obj apilib.lib + $(MAKE) haribote.img -color2.hrb : color2.bim Makefile - $(BIM2HRB) color2.bim color2.hrb 56k +#文件生成规则 -haribote.img : ipl10.bin haribote.sys Makefile \ - a.hrb hello3.hrb hello4.hrb hello5.hrb winhelo.hrb winhelo2.hrb \ - winhelo3.hrb star1.hrb stars.hrb stars2.hrb lines.hrb walk.hrb \ - noodle.hrb beepdown.hrb color.hrb color2.hrb +haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ + a/a.hrb hello3/hello3.hrb hello4/hello4.hrb hello5/hello5.hrb \ + winhelo/winhelo.hrb winhelo2/winhelo2.hrb winhelo3/winhelo3.hrb \ + star1/star1.hrb stars/stars.hrb stars2/stars2.hrb \ + lines/lines.hrb walk/walk.hrb noodle/noodle.hrb \ + beepdown/beepdown.hrb color/color.hrb color2/color2.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ - wbinimg src:ipl10.bin len:512 from:0 to:0 \ - copy from:haribote.sys to:@: \ - copy from:ipl10.nas to:@: \ + wbinimg src:haribote/ipl10.bin len:512 from:0 to:0 \ + copy from:haribote/haribote.sys to:@: \ + copy from:haribote/ipl10.nas to:@: \ copy from:make.bat to:@: \ - copy from:a.hrb to:@: \ - copy from:hello3.hrb to:@: \ - copy from:hello4.hrb to:@: \ - copy from:hello5.hrb to:@: \ - copy from:winhelo.hrb to:@: \ - copy from:winhelo2.hrb to:@: \ - copy from:winhelo3.hrb to:@: \ - copy from:star1.hrb to:@: \ - copy from:stars.hrb to:@: \ - copy from:stars2.hrb to:@: \ - copy from:lines.hrb to:@: \ - copy from:walk.hrb to:@: \ - copy from:noodle.hrb to:@: \ - copy from:beepdown.hrb to:@: \ - copy from:color.hrb to:@: \ - copy from:color2.hrb to:@: \ + copy from:a/a.hrb to:@: \ + copy from:hello3/hello3.hrb to:@: \ + copy from:hello4/hello4.hrb to:@: \ + copy from:hello5/hello5.hrb to:@: \ + copy from:winhelo/winhelo.hrb to:@: \ + copy from:winhelo2/winhelo2.hrb to:@: \ + copy from:winhelo3/winhelo3.hrb to:@: \ + copy from:star1/star1.hrb to:@: \ + copy from:stars/stars.hrb to:@: \ + copy from:stars2/stars2.hrb to:@: \ + copy from:lines/lines.hrb to:@: \ + copy from:walk/walk.hrb to:@: \ + copy from:noodle/noodle.hrb to:@: \ + copy from:beepdown/beepdown.hrb to:@: \ + copy from:color/color.hrb to:@: \ + copy from:color2/color2.hrb to:@: \ imgout:haribote.img -# ʋK - -%.gas : %.c bootpack.h apilib.h Makefile - $(CC1) -o $*.gas $*.c - -%.nas : %.gas Makefile - $(GAS2NASK) $*.gas $*.nas +#命令 -%.obj : %.nas Makefile - $(NASK) $*.nas $*.obj $*.lst +run : + $(MAKE) haribote.img + $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../z_tools/qemu -# R}h +install : + $(MAKE) haribote.img + $(IMGTOL) w a: haribote.img -img : +full : + $(MAKE) -C haribote + $(MAKE) -C apilib + $(MAKE) -C a + $(MAKE) -C hello3 + $(MAKE) -C hello4 + $(MAKE) -C hello5 + $(MAKE) -C winhelo + $(MAKE) -C winhelo2 + $(MAKE) -C winhelo3 + $(MAKE) -C star1 + $(MAKE) -C stars + $(MAKE) -C stars2 + $(MAKE) -C lines + $(MAKE) -C walk + $(MAKE) -C noodle + $(MAKE) -C beepdown + $(MAKE) -C color + $(MAKE) -C color2 $(MAKE) haribote.img -run : - $(MAKE) img +run_full : + $(MAKE) full $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin $(MAKE) -C ../z_tools/qemu -install : - $(MAKE) img +install_full : + $(MAKE) full $(IMGTOL) w a: haribote.img +run_os : + $(MAKE) -C haribote + $(MAKE) run + clean : - -$(DEL) *.bin - -$(DEL) *.lst - -$(DEL) *.obj - -$(DEL) *.map - -$(DEL) *.bim - -$(DEL) *.hrb - -$(DEL) haribote.sys - -$(DEL) apilib.lib +#不执行任何操作 src_only : $(MAKE) clean -$(DEL) haribote.img + +clean_full : + $(MAKE) -C haribote clean + $(MAKE) -C apilib clean + $(MAKE) -C a clean + $(MAKE) -C hello3 clean + $(MAKE) -C hello4 clean + $(MAKE) -C hello5 clean + $(MAKE) -C winhelo clean + $(MAKE) -C winhelo2 clean + $(MAKE) -C winhelo3 clean + $(MAKE) -C star1 clean + $(MAKE) -C stars clean + $(MAKE) -C stars2 clean + $(MAKE) -C lines clean + $(MAKE) -C walk clean + $(MAKE) -C noodle clean + $(MAKE) -C beepdown clean + $(MAKE) -C color clean + $(MAKE) -C color2 clean + +src_only_full : + $(MAKE) -C haribote src_only + $(MAKE) -C apilib src_only + $(MAKE) -C a src_only + $(MAKE) -C hello3 src_only + $(MAKE) -C hello4 src_only + $(MAKE) -C hello5 src_only + $(MAKE) -C winhelo src_only + $(MAKE) -C winhelo2 src_only + $(MAKE) -C winhelo3 src_only + $(MAKE) -C star1 src_only + $(MAKE) -C stars src_only + $(MAKE) -C stars2 src_only + $(MAKE) -C lines src_only + $(MAKE) -C walk src_only + $(MAKE) -C noodle src_only + $(MAKE) -C beepdown src_only + $(MAKE) -C color src_only + $(MAKE) -C color2 src_only + -$(DEL) haribote.img + +refresh : + $(MAKE) full + $(MAKE) clean_full + -$(DEL) haribote.img diff --git a/27_day/a/!cons_9x.bat b/27_day/a/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/27_day/a/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/27_day/a/!cons_nt.bat b/27_day/a/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/27_day/a/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/27_day/a/Makefile b/27_day/a/Makefile new file mode 100644 index 0000000..674a683 --- /dev/null +++ b/27_day/a/Makefile @@ -0,0 +1,5 @@ +APP = a +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/27_day/a.c b/27_day/a/a.c similarity index 100% rename from 27_day/a.c rename to 27_day/a/a.c diff --git a/27_day/a/make.bat b/27_day/a/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/27_day/a/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/27_day/apilib/!cons_9x.bat b/27_day/apilib/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/27_day/apilib/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/27_day/apilib/!cons_nt.bat b/27_day/apilib/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/27_day/apilib/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/27_day/apilib/Makefile b/27_day/apilib/Makefile new file mode 100644 index 0000000..e93248b --- /dev/null +++ b/27_day/apilib/Makefile @@ -0,0 +1,47 @@ +OBJS_API = api001.obj api002.obj api003.obj api004.obj api005.obj api006.obj \ + api007.obj api008.obj api009.obj api010.obj api011.obj api012.obj \ + api013.obj api014.obj api015.obj api016.obj api017.obj api018.obj \ + api019.obj api020.obj + +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +# ftHg + +default : + $(MAKE) apilib.lib + +# t@CK + +apilib.lib : Makefile $(OBJS_API) + $(GOLIB) $(OBJS_API) out:apilib.lib + +# ʋK + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +# R}h + +clean : + -$(DEL) *.lst + -$(DEL) *.obj + +src_only : + $(MAKE) clean + -$(DEL) apilib.lib diff --git a/27_day/api001.nas b/27_day/apilib/api001.nas similarity index 100% rename from 27_day/api001.nas rename to 27_day/apilib/api001.nas diff --git a/27_day/api002.nas b/27_day/apilib/api002.nas similarity index 100% rename from 27_day/api002.nas rename to 27_day/apilib/api002.nas diff --git a/27_day/api003.nas b/27_day/apilib/api003.nas similarity index 100% rename from 27_day/api003.nas rename to 27_day/apilib/api003.nas diff --git a/27_day/api004.nas b/27_day/apilib/api004.nas similarity index 100% rename from 27_day/api004.nas rename to 27_day/apilib/api004.nas diff --git a/27_day/api005.nas b/27_day/apilib/api005.nas similarity index 100% rename from 27_day/api005.nas rename to 27_day/apilib/api005.nas diff --git a/27_day/api006.nas b/27_day/apilib/api006.nas similarity index 100% rename from 27_day/api006.nas rename to 27_day/apilib/api006.nas diff --git a/27_day/api007.nas b/27_day/apilib/api007.nas similarity index 100% rename from 27_day/api007.nas rename to 27_day/apilib/api007.nas diff --git a/27_day/api008.nas b/27_day/apilib/api008.nas similarity index 100% rename from 27_day/api008.nas rename to 27_day/apilib/api008.nas diff --git a/27_day/api009.nas b/27_day/apilib/api009.nas similarity index 100% rename from 27_day/api009.nas rename to 27_day/apilib/api009.nas diff --git a/27_day/api010.nas b/27_day/apilib/api010.nas similarity index 100% rename from 27_day/api010.nas rename to 27_day/apilib/api010.nas diff --git a/27_day/api011.nas b/27_day/apilib/api011.nas similarity index 100% rename from 27_day/api011.nas rename to 27_day/apilib/api011.nas diff --git a/27_day/api012.nas b/27_day/apilib/api012.nas similarity index 100% rename from 27_day/api012.nas rename to 27_day/apilib/api012.nas diff --git a/27_day/api013.nas b/27_day/apilib/api013.nas similarity index 100% rename from 27_day/api013.nas rename to 27_day/apilib/api013.nas diff --git a/27_day/api014.nas b/27_day/apilib/api014.nas similarity index 100% rename from 27_day/api014.nas rename to 27_day/apilib/api014.nas diff --git a/27_day/api015.nas b/27_day/apilib/api015.nas similarity index 100% rename from 27_day/api015.nas rename to 27_day/apilib/api015.nas diff --git a/27_day/api016.nas b/27_day/apilib/api016.nas similarity index 100% rename from 27_day/api016.nas rename to 27_day/apilib/api016.nas diff --git a/27_day/api017.nas b/27_day/apilib/api017.nas similarity index 100% rename from 27_day/api017.nas rename to 27_day/apilib/api017.nas diff --git a/27_day/api018.nas b/27_day/apilib/api018.nas similarity index 100% rename from 27_day/api018.nas rename to 27_day/apilib/api018.nas diff --git a/27_day/api019.nas b/27_day/apilib/api019.nas similarity index 100% rename from 27_day/api019.nas rename to 27_day/apilib/api019.nas diff --git a/27_day/api020.nas b/27_day/apilib/api020.nas similarity index 100% rename from 27_day/api020.nas rename to 27_day/apilib/api020.nas diff --git a/27_day/apilib/apilib.lib b/27_day/apilib/apilib.lib new file mode 100644 index 0000000000000000000000000000000000000000..29a8eeebd154eb753bb6d0e59a2125dff5d57df1 GIT binary patch literal 8966 zcmeI2&uv5w%5XY3zgzHW)jywS}zIi{^ zs~^`oyY){J*V10ed5ca-)fYK*TCxI?b?20d;e=|w_fW&6}na@=PnqsV7Bha zllH#Z`liuxcX5h4?T34frc-RR8rFkav)SI2z1`<~9n-YOXg6AxJnfiN-K{$VG#f3` zDeN}e-9hQDY27!!m6wTISd9m!{SkCHS})$E;`RZ|rK z#|@ljv<` zk{TKXJq@0(S4Kv|fTU3jLBsIt#Z#JokY1dkHm1RSlte+J&l|wuM!?oo)Fa?YdgWaq z5Jr@J91^)TiH%C^Mx_v|Uh=Q{?=)o4s((anyz1OXNffL8`Da^wa!*(bQavlP)H}#5 z_bQnc(ug!^#8=xvJ5)&zgy-*-cLjt;4X_o;1C=^a4ne2vx7mNteS+v*rZ%R-eUwB) z=hLk|d5(-{iSR5Fo)yBACOny5Gjo{`-413{)-&R#@Je)y7U@RHA0;cozPqG!{eMD< zcOXHjLX}Af!2ca!tG6Ds^wv0udn73()F@y8O#*o;b z_d>5k$H8&G?9V=eLYT<^1PVXU?+X7jr?#AXi()kkTw9nBbg=@*)j4->8D{hBcrR-3nB Wt<|Qd)cUcbwAxHvcu(R_7XJe03V>?> literal 0 HcmV?d00001 diff --git a/27_day/apilib/make.bat b/27_day/apilib/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/27_day/apilib/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/27_day/app_make.txt b/27_day/app_make.txt new file mode 100644 index 0000000..2bca4bc --- /dev/null +++ b/27_day/app_make.txt @@ -0,0 +1,79 @@ +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ +APILIBPATH = ../apilib/ +HARIBOTEPATH = ../haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -I../ -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) $(APP).hrb + +#文件生成规则 + +$(APP).bim : $(APP).obj $(APILIBPATH)apilib.lib Makefile ../app_make.txt + $(OBJ2BIM) @$(RULEFILE) out:$(APP).bim map:$(APP).map stack:$(STACK) \ + $(APP).obj $(APILIBPATH)apilib.lib + +$(APP).hrb : $(APP).bim Makefile ../app_make.txt + $(BIM2HRB) $(APP).bim $(APP).hrb $(MALLOC) + +haribote.img : ../haribote/ipl10.bin ../haribote/haribote.sys $(APP).hrb \ + Makefile ../app_make.txt + $(EDIMG) imgin:../../z_tools/fdimg0at.tek \ + wbinimg src:../haribote/ipl10.bin len:512 from:0 to:0 \ + copy from:../haribote/haribote.sys to:@: \ + copy from:$(APP).hrb to:@: \ + imgout:haribote.img + +#一般规则 + +%.gas : %.c ../apilib.h Makefile ../app_make.txt + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile ../app_make.txt + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile ../app_make.txt + $(NASK) $*.nas $*.obj $*.lst + +#命令 + +run : + $(MAKE) haribote.img + $(COPY) haribote.img ..\..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../../z_tools/qemu + +full : + $(MAKE) -C $(APILIBPATH) + $(MAKE) $(APP).hrb + +run_full : + $(MAKE) -C $(APILIBPATH) + $(MAKE) -C ../haribote + $(MAKE) run + +clean : + -$(DEL) *.lst + -$(DEL) *.obj + -$(DEL) *.map + -$(DEL) *.bim + -$(DEL) haribote.img + +src_only : + $(MAKE) clean + -$(DEL) $(APP).hrb diff --git a/27_day/beepdown/!cons_9x.bat b/27_day/beepdown/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/27_day/beepdown/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/27_day/beepdown/!cons_nt.bat b/27_day/beepdown/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/27_day/beepdown/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/27_day/beepdown/Makefile b/27_day/beepdown/Makefile new file mode 100644 index 0000000..ffd14fa --- /dev/null +++ b/27_day/beepdown/Makefile @@ -0,0 +1,5 @@ +APP = beepdown +STACK = 1k +MALLOC = 40k + +include ../app_make.txt diff --git a/27_day/beepdown.c b/27_day/beepdown/beepdown.c similarity index 100% rename from 27_day/beepdown.c rename to 27_day/beepdown/beepdown.c diff --git a/27_day/beepdown/make.bat b/27_day/beepdown/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/27_day/beepdown/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/27_day/color/!cons_9x.bat b/27_day/color/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/27_day/color/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/27_day/color/!cons_nt.bat b/27_day/color/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/27_day/color/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/27_day/color/Makefile b/27_day/color/Makefile new file mode 100644 index 0000000..614dac9 --- /dev/null +++ b/27_day/color/Makefile @@ -0,0 +1,5 @@ +APP = color +STACK = 1k +MALLOC = 56k + +include ../app_make.txt diff --git a/27_day/color.c b/27_day/color/color.c similarity index 100% rename from 27_day/color.c rename to 27_day/color/color.c diff --git a/27_day/color/make.bat b/27_day/color/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/27_day/color/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/27_day/color2/!cons_9x.bat b/27_day/color2/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/27_day/color2/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/27_day/color2/!cons_nt.bat b/27_day/color2/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/27_day/color2/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/27_day/color2/Makefile b/27_day/color2/Makefile new file mode 100644 index 0000000..93b5f23 --- /dev/null +++ b/27_day/color2/Makefile @@ -0,0 +1,5 @@ +APP = color2 +STACK = 1k +MALLOC = 56k + +include ../app_make.txt diff --git a/27_day/color2.c b/27_day/color2/color2.c similarity index 100% rename from 27_day/color2.c rename to 27_day/color2/color2.c diff --git a/27_day/color2/make.bat b/27_day/color2/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/27_day/color2/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/27_day/haribote.rul b/27_day/haribote.rul new file mode 100644 index 0000000..ee8f67b --- /dev/null +++ b/27_day/haribote.rul @@ -0,0 +1,10 @@ +format: + code(align:1, logic:0x24, file:0x24); + data(align:4, logic:stack_end, file:code_end); + +file: + ../../z_tools/haribote/harilibc.lib; + ../../z_tools/haribote/golibc.lib; + +label: + _HariStartup; diff --git a/27_day/haribote/!cons_9x.bat b/27_day/haribote/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/27_day/haribote/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/27_day/haribote/!cons_nt.bat b/27_day/haribote/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/27_day/haribote/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/27_day/haribote/Makefile b/27_day/haribote/Makefile new file mode 100644 index 0000000..b0ce461 --- /dev/null +++ b/27_day/haribote/Makefile @@ -0,0 +1,79 @@ +OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \ + int.obj fifo.obj keyboard.obj mouse.obj memory.obj sheet.obj timer.obj \ + mtask.obj window.obj console.obj file.obj + +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) ipl10.bin + $(MAKE) haribote.sys + +# 镜像文件生成 + +ipl10.bin : ipl10.nas Makefile + $(NASK) ipl10.nas ipl10.bin ipl10.lst + +asmhead.bin : asmhead.nas Makefile + $(NASK) asmhead.nas asmhead.bin asmhead.lst + +hankaku.bin : hankaku.txt Makefile + $(MAKEFONT) hankaku.txt hankaku.bin + +hankaku.obj : hankaku.bin Makefile + $(BIN2OBJ) hankaku.bin hankaku.obj _hankaku + +bootpack.bim : $(OBJS_BOOTPACK) Makefile + $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \ + $(OBJS_BOOTPACK) +# 3MB+64KB=3136KB + +bootpack.hrb : bootpack.bim Makefile + $(BIM2HRB) bootpack.bim bootpack.hrb 0 + +haribote.sys : asmhead.bin bootpack.hrb Makefile + copy /B asmhead.bin+bootpack.hrb haribote.sys + +# 其他指令 + +%.gas : %.c bootpack.h Makefile + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +# 运行程序 + +clean : + -$(DEL) asmhead.bin + -$(DEL) hankaku.bin + -$(DEL) *.lst + -$(DEL) *.obj + -$(DEL) *.map + -$(DEL) *.bim + -$(DEL) *.hrb + +src_only : + $(MAKE) clean + -$(DEL) ipl10.bin + -$(DEL) haribote.sys diff --git a/27_day/asmhead.nas b/27_day/haribote/asmhead.nas similarity index 100% rename from 27_day/asmhead.nas rename to 27_day/haribote/asmhead.nas diff --git a/27_day/bootpack.c b/27_day/haribote/bootpack.c similarity index 100% rename from 27_day/bootpack.c rename to 27_day/haribote/bootpack.c diff --git a/27_day/bootpack.h b/27_day/haribote/bootpack.h similarity index 100% rename from 27_day/bootpack.h rename to 27_day/haribote/bootpack.h diff --git a/27_day/console.c b/27_day/haribote/console.c similarity index 100% rename from 27_day/console.c rename to 27_day/haribote/console.c diff --git a/27_day/dsctbl.c b/27_day/haribote/dsctbl.c similarity index 100% rename from 27_day/dsctbl.c rename to 27_day/haribote/dsctbl.c diff --git a/27_day/fifo.c b/27_day/haribote/fifo.c similarity index 100% rename from 27_day/fifo.c rename to 27_day/haribote/fifo.c diff --git a/27_day/file.c b/27_day/haribote/file.c similarity index 100% rename from 27_day/file.c rename to 27_day/haribote/file.c diff --git a/27_day/graphic.c b/27_day/haribote/graphic.c similarity index 100% rename from 27_day/graphic.c rename to 27_day/haribote/graphic.c diff --git a/27_day/hankaku.txt b/27_day/haribote/hankaku.txt similarity index 100% rename from 27_day/hankaku.txt rename to 27_day/haribote/hankaku.txt diff --git a/27_day/haribote/haribote.sys b/27_day/haribote/haribote.sys new file mode 100644 index 0000000000000000000000000000000000000000..e098d2b2dc72ce95ff296ef38e8f320f59a0abbd GIT binary patch literal 33331 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 Date: Wed, 18 May 2016 10:25:37 +0800 Subject: [PATCH 44/83] Add 28 day code --- 28_day/!cons_9x.bat | 1 + 28_day/!cons_nt.bat | 1 + 28_day/Makefile | 142 ++ 28_day/a/!cons_9x.bat | 1 + 28_day/a/!cons_nt.bat | 1 + 28_day/a/Makefile | 5 + 28_day/a/a.c | 7 + 28_day/a/make.bat | 1 + 28_day/apilib.h | 20 + 28_day/apilib/!cons_9x.bat | 1 + 28_day/apilib/!cons_nt.bat | 1 + 28_day/apilib/Makefile | 47 + 28_day/apilib/api001.nas | 14 + 28_day/apilib/api002.nas | 16 + 28_day/apilib/api003.nas | 17 + 28_day/apilib/api004.nas | 12 + 28_day/apilib/api005.nas | 24 + 28_day/apilib/api006.nas | 27 + 28_day/apilib/api007.nas | 27 + 28_day/apilib/api008.nas | 20 + 28_day/apilib/api009.nas | 17 + 28_day/apilib/api010.nas | 18 + 28_day/apilib/api011.nas | 23 + 28_day/apilib/api012.nas | 24 + 28_day/apilib/api013.nas | 27 + 28_day/apilib/api014.nas | 16 + 28_day/apilib/api015.nas | 14 + 28_day/apilib/api016.nas | 13 + 28_day/apilib/api017.nas | 17 + 28_day/apilib/api018.nas | 17 + 28_day/apilib/api019.nas | 16 + 28_day/apilib/api020.nas | 14 + 28_day/apilib/apilib.lib | Bin 0 -> 8966 bytes 28_day/apilib/make.bat | 1 + 28_day/app_make.txt | 79 + 28_day/beepdown/!cons_9x.bat | 1 + 28_day/beepdown/!cons_nt.bat | 1 + 28_day/beepdown/Makefile | 5 + 28_day/beepdown/beepdown.c | 19 + 28_day/beepdown/make.bat | 1 + 28_day/color/!cons_9x.bat | 1 + 28_day/color/!cons_nt.bat | 1 + 28_day/color/Makefile | 5 + 28_day/color/color.c | 21 + 28_day/color/make.bat | 1 + 28_day/color2/!cons_9x.bat | 1 + 28_day/color2/!cons_nt.bat | 1 + 28_day/color2/Makefile | 5 + 28_day/color2/color2.c | 36 + 28_day/color2/make.bat | 1 + 28_day/haribote.rul | 10 + 28_day/haribote/!cons_9x.bat | 1 + 28_day/haribote/!cons_nt.bat | 1 + 28_day/haribote/Makefile | 79 + 28_day/haribote/asmhead.nas | 202 ++ 28_day/haribote/bootpack.c | 387 +++ 28_day/haribote/bootpack.h | 283 +++ 28_day/haribote/console.c | 604 +++++ 28_day/haribote/dsctbl.c | 59 + 28_day/haribote/fifo.c | 63 + 28_day/haribote/file.c | 74 + 28_day/haribote/graphic.c | 167 ++ 28_day/haribote/hankaku.txt | 4609 ++++++++++++++++++++++++++++++++++ 28_day/haribote/haribote.sys | Bin 0 -> 33331 bytes 28_day/haribote/int.c | 26 + 28_day/haribote/ipl10.bin | Bin 0 -> 512 bytes 28_day/haribote/ipl10.nas | 109 + 28_day/haribote/keyboard.c | 44 + 28_day/haribote/make.bat | 1 + 28_day/haribote/memory.c | 162 ++ 28_day/haribote/mouse.c | 76 + 28_day/haribote/mtask.c | 203 ++ 28_day/haribote/naskfunc.nas | 291 +++ 28_day/haribote/sheet.c | 294 +++ 28_day/haribote/timer.c | 169 ++ 28_day/haribote/window.c | 118 + 28_day/hello3/!cons_9x.bat | 1 + 28_day/hello3/!cons_nt.bat | 1 + 28_day/hello3/Makefile | 5 + 28_day/hello3/hello3.c | 11 + 28_day/hello3/make.bat | 1 + 28_day/hello4/!cons_9x.bat | 1 + 28_day/hello4/!cons_nt.bat | 1 + 28_day/hello4/Makefile | 5 + 28_day/hello4/hello4.c | 7 + 28_day/hello4/make.bat | 1 + 28_day/hello5/!cons_9x.bat | 1 + 28_day/hello5/!cons_nt.bat | 1 + 28_day/hello5/Makefile | 5 + 28_day/hello5/hello5.nas | 20 + 28_day/hello5/make.bat | 1 + 28_day/lines/!cons_9x.bat | 1 + 28_day/lines/!cons_nt.bat | 1 + 28_day/lines/Makefile | 5 + 28_day/lines/lines.c | 22 + 28_day/lines/make.bat | 1 + 28_day/make.bat | 1 + 28_day/noodle/!cons_9x.bat | 1 + 28_day/noodle/!cons_nt.bat | 1 + 28_day/noodle/Makefile | 5 + 28_day/noodle/make.bat | 1 + 28_day/noodle/noodle.c | 32 + 28_day/star1/!cons_9x.bat | 1 + 28_day/star1/!cons_nt.bat | 1 + 28_day/star1/Makefile | 5 + 28_day/star1/make.bat | 1 + 28_day/star1/star1.c | 18 + 28_day/stars/!cons_9x.bat | 1 + 28_day/stars/!cons_nt.bat | 1 + 28_day/stars/Makefile | 5 + 28_day/stars/make.bat | 1 + 28_day/stars/stars.c | 24 + 28_day/stars2/!cons_9x.bat | 1 + 28_day/stars2/!cons_nt.bat | 1 + 28_day/stars2/Makefile | 5 + 28_day/stars2/make.bat | 1 + 28_day/stars2/stars2.c | 25 + 28_day/walk/!cons_9x.bat | 1 + 28_day/walk/!cons_nt.bat | 1 + 28_day/walk/Makefile | 5 + 28_day/walk/make.bat | 1 + 28_day/walk/walk.c | 26 + 28_day/winhelo/!cons_9x.bat | 1 + 28_day/winhelo/!cons_nt.bat | 1 + 28_day/winhelo/Makefile | 5 + 28_day/winhelo/make.bat | 1 + 28_day/winhelo/winhelo.c | 15 + 28_day/winhelo2/!cons_9x.bat | 1 + 28_day/winhelo2/!cons_nt.bat | 1 + 28_day/winhelo2/Makefile | 5 + 28_day/winhelo2/make.bat | 1 + 28_day/winhelo2/winhelo2.c | 17 + 28_day/winhelo3/!cons_9x.bat | 1 + 28_day/winhelo3/!cons_nt.bat | 1 + 28_day/winhelo3/Makefile | 5 + 28_day/winhelo3/make.bat | 1 + 28_day/winhelo3/winhelo3.c | 19 + 137 files changed, 9146 insertions(+) create mode 100644 28_day/!cons_9x.bat create mode 100644 28_day/!cons_nt.bat create mode 100644 28_day/Makefile create mode 100644 28_day/a/!cons_9x.bat create mode 100644 28_day/a/!cons_nt.bat create mode 100644 28_day/a/Makefile create mode 100644 28_day/a/a.c create mode 100644 28_day/a/make.bat create mode 100644 28_day/apilib.h create mode 100644 28_day/apilib/!cons_9x.bat create mode 100644 28_day/apilib/!cons_nt.bat create mode 100644 28_day/apilib/Makefile create mode 100644 28_day/apilib/api001.nas create mode 100644 28_day/apilib/api002.nas create mode 100644 28_day/apilib/api003.nas create mode 100644 28_day/apilib/api004.nas create mode 100644 28_day/apilib/api005.nas create mode 100644 28_day/apilib/api006.nas create mode 100644 28_day/apilib/api007.nas create mode 100644 28_day/apilib/api008.nas create mode 100644 28_day/apilib/api009.nas create mode 100644 28_day/apilib/api010.nas create mode 100644 28_day/apilib/api011.nas create mode 100644 28_day/apilib/api012.nas create mode 100644 28_day/apilib/api013.nas create mode 100644 28_day/apilib/api014.nas create mode 100644 28_day/apilib/api015.nas create mode 100644 28_day/apilib/api016.nas create mode 100644 28_day/apilib/api017.nas create mode 100644 28_day/apilib/api018.nas create mode 100644 28_day/apilib/api019.nas create mode 100644 28_day/apilib/api020.nas create mode 100644 28_day/apilib/apilib.lib create mode 100644 28_day/apilib/make.bat create mode 100644 28_day/app_make.txt create mode 100644 28_day/beepdown/!cons_9x.bat create mode 100644 28_day/beepdown/!cons_nt.bat create mode 100644 28_day/beepdown/Makefile create mode 100644 28_day/beepdown/beepdown.c create mode 100644 28_day/beepdown/make.bat create mode 100644 28_day/color/!cons_9x.bat create mode 100644 28_day/color/!cons_nt.bat create mode 100644 28_day/color/Makefile create mode 100644 28_day/color/color.c create mode 100644 28_day/color/make.bat create mode 100644 28_day/color2/!cons_9x.bat create mode 100644 28_day/color2/!cons_nt.bat create mode 100644 28_day/color2/Makefile create mode 100644 28_day/color2/color2.c create mode 100644 28_day/color2/make.bat create mode 100644 28_day/haribote.rul create mode 100644 28_day/haribote/!cons_9x.bat create mode 100644 28_day/haribote/!cons_nt.bat create mode 100644 28_day/haribote/Makefile create mode 100644 28_day/haribote/asmhead.nas create mode 100644 28_day/haribote/bootpack.c create mode 100644 28_day/haribote/bootpack.h create mode 100644 28_day/haribote/console.c create mode 100644 28_day/haribote/dsctbl.c create mode 100644 28_day/haribote/fifo.c create mode 100644 28_day/haribote/file.c create mode 100644 28_day/haribote/graphic.c create mode 100644 28_day/haribote/hankaku.txt create mode 100644 28_day/haribote/haribote.sys create mode 100644 28_day/haribote/int.c create mode 100644 28_day/haribote/ipl10.bin create mode 100644 28_day/haribote/ipl10.nas create mode 100644 28_day/haribote/keyboard.c create mode 100644 28_day/haribote/make.bat create mode 100644 28_day/haribote/memory.c create mode 100644 28_day/haribote/mouse.c create mode 100644 28_day/haribote/mtask.c create mode 100644 28_day/haribote/naskfunc.nas create mode 100644 28_day/haribote/sheet.c create mode 100644 28_day/haribote/timer.c create mode 100644 28_day/haribote/window.c create mode 100644 28_day/hello3/!cons_9x.bat create mode 100644 28_day/hello3/!cons_nt.bat create mode 100644 28_day/hello3/Makefile create mode 100644 28_day/hello3/hello3.c create mode 100644 28_day/hello3/make.bat create mode 100644 28_day/hello4/!cons_9x.bat create mode 100644 28_day/hello4/!cons_nt.bat create mode 100644 28_day/hello4/Makefile create mode 100644 28_day/hello4/hello4.c create mode 100644 28_day/hello4/make.bat create mode 100644 28_day/hello5/!cons_9x.bat create mode 100644 28_day/hello5/!cons_nt.bat create mode 100644 28_day/hello5/Makefile create mode 100644 28_day/hello5/hello5.nas create mode 100644 28_day/hello5/make.bat create mode 100644 28_day/lines/!cons_9x.bat create mode 100644 28_day/lines/!cons_nt.bat create mode 100644 28_day/lines/Makefile create mode 100644 28_day/lines/lines.c create mode 100644 28_day/lines/make.bat create mode 100644 28_day/make.bat create mode 100644 28_day/noodle/!cons_9x.bat create mode 100644 28_day/noodle/!cons_nt.bat create mode 100644 28_day/noodle/Makefile create mode 100644 28_day/noodle/make.bat create mode 100644 28_day/noodle/noodle.c create mode 100644 28_day/star1/!cons_9x.bat create mode 100644 28_day/star1/!cons_nt.bat create mode 100644 28_day/star1/Makefile create mode 100644 28_day/star1/make.bat create mode 100644 28_day/star1/star1.c create mode 100644 28_day/stars/!cons_9x.bat create mode 100644 28_day/stars/!cons_nt.bat create mode 100644 28_day/stars/Makefile create mode 100644 28_day/stars/make.bat create mode 100644 28_day/stars/stars.c create mode 100644 28_day/stars2/!cons_9x.bat create mode 100644 28_day/stars2/!cons_nt.bat create mode 100644 28_day/stars2/Makefile create mode 100644 28_day/stars2/make.bat create mode 100644 28_day/stars2/stars2.c create mode 100644 28_day/walk/!cons_9x.bat create mode 100644 28_day/walk/!cons_nt.bat create mode 100644 28_day/walk/Makefile create mode 100644 28_day/walk/make.bat create mode 100644 28_day/walk/walk.c create mode 100644 28_day/winhelo/!cons_9x.bat create mode 100644 28_day/winhelo/!cons_nt.bat create mode 100644 28_day/winhelo/Makefile create mode 100644 28_day/winhelo/make.bat create mode 100644 28_day/winhelo/winhelo.c create mode 100644 28_day/winhelo2/!cons_9x.bat create mode 100644 28_day/winhelo2/!cons_nt.bat create mode 100644 28_day/winhelo2/Makefile create mode 100644 28_day/winhelo2/make.bat create mode 100644 28_day/winhelo2/winhelo2.c create mode 100644 28_day/winhelo3/!cons_9x.bat create mode 100644 28_day/winhelo3/!cons_nt.bat create mode 100644 28_day/winhelo3/Makefile create mode 100644 28_day/winhelo3/make.bat create mode 100644 28_day/winhelo3/winhelo3.c diff --git a/28_day/!cons_9x.bat b/28_day/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/!cons_nt.bat b/28_day/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/Makefile b/28_day/Makefile new file mode 100644 index 0000000..23e155c --- /dev/null +++ b/28_day/Makefile @@ -0,0 +1,142 @@ +TOOLPATH = ../z_tools/ +INCPATH = ../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) haribote.img + +#文件生成规则 + +haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ + a/a.hrb hello3/hello3.hrb hello4/hello4.hrb hello5/hello5.hrb \ + winhelo/winhelo.hrb winhelo2/winhelo2.hrb winhelo3/winhelo3.hrb \ + star1/star1.hrb stars/stars.hrb stars2/stars2.hrb \ + lines/lines.hrb walk/walk.hrb noodle/noodle.hrb \ + beepdown/beepdown.hrb color/color.hrb color2/color2.hrb + $(EDIMG) imgin:../z_tools/fdimg0at.tek \ + wbinimg src:haribote/ipl10.bin len:512 from:0 to:0 \ + copy from:haribote/haribote.sys to:@: \ + copy from:haribote/ipl10.nas to:@: \ + copy from:make.bat to:@: \ + copy from:a/a.hrb to:@: \ + copy from:hello3/hello3.hrb to:@: \ + copy from:hello4/hello4.hrb to:@: \ + copy from:hello5/hello5.hrb to:@: \ + copy from:winhelo/winhelo.hrb to:@: \ + copy from:winhelo2/winhelo2.hrb to:@: \ + copy from:winhelo3/winhelo3.hrb to:@: \ + copy from:star1/star1.hrb to:@: \ + copy from:stars/stars.hrb to:@: \ + copy from:stars2/stars2.hrb to:@: \ + copy from:lines/lines.hrb to:@: \ + copy from:walk/walk.hrb to:@: \ + copy from:noodle/noodle.hrb to:@: \ + copy from:beepdown/beepdown.hrb to:@: \ + copy from:color/color.hrb to:@: \ + copy from:color2/color2.hrb to:@: \ + imgout:haribote.img + +#命令 + +run : + $(MAKE) haribote.img + $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../z_tools/qemu + +install : + $(MAKE) haribote.img + $(IMGTOL) w a: haribote.img + +full : + $(MAKE) -C haribote + $(MAKE) -C apilib + $(MAKE) -C a + $(MAKE) -C hello3 + $(MAKE) -C hello4 + $(MAKE) -C hello5 + $(MAKE) -C winhelo + $(MAKE) -C winhelo2 + $(MAKE) -C winhelo3 + $(MAKE) -C star1 + $(MAKE) -C stars + $(MAKE) -C stars2 + $(MAKE) -C lines + $(MAKE) -C walk + $(MAKE) -C noodle + $(MAKE) -C beepdown + $(MAKE) -C color + $(MAKE) -C color2 + $(MAKE) haribote.img + +run_full : + $(MAKE) full + $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../z_tools/qemu + +install_full : + $(MAKE) full + $(IMGTOL) w a: haribote.img + +run_os : + $(MAKE) -C haribote + $(MAKE) run + +clean : +#不执行任何操作 + +src_only : + $(MAKE) clean + -$(DEL) haribote.img + +clean_full : + $(MAKE) -C haribote clean + $(MAKE) -C apilib clean + $(MAKE) -C a clean + $(MAKE) -C hello3 clean + $(MAKE) -C hello4 clean + $(MAKE) -C hello5 clean + $(MAKE) -C winhelo clean + $(MAKE) -C winhelo2 clean + $(MAKE) -C winhelo3 clean + $(MAKE) -C star1 clean + $(MAKE) -C stars clean + $(MAKE) -C stars2 clean + $(MAKE) -C lines clean + $(MAKE) -C walk clean + $(MAKE) -C noodle clean + $(MAKE) -C beepdown clean + $(MAKE) -C color clean + $(MAKE) -C color2 clean + +src_only_full : + $(MAKE) -C haribote src_only + $(MAKE) -C apilib src_only + $(MAKE) -C a src_only + $(MAKE) -C hello3 src_only + $(MAKE) -C hello4 src_only + $(MAKE) -C hello5 src_only + $(MAKE) -C winhelo src_only + $(MAKE) -C winhelo2 src_only + $(MAKE) -C winhelo3 src_only + $(MAKE) -C star1 src_only + $(MAKE) -C stars src_only + $(MAKE) -C stars2 src_only + $(MAKE) -C lines src_only + $(MAKE) -C walk src_only + $(MAKE) -C noodle src_only + $(MAKE) -C beepdown src_only + $(MAKE) -C color src_only + $(MAKE) -C color2 src_only + -$(DEL) haribote.img + +refresh : + $(MAKE) full + $(MAKE) clean_full + -$(DEL) haribote.img diff --git a/28_day/a/!cons_9x.bat b/28_day/a/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/a/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/a/!cons_nt.bat b/28_day/a/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/a/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/a/Makefile b/28_day/a/Makefile new file mode 100644 index 0000000..674a683 --- /dev/null +++ b/28_day/a/Makefile @@ -0,0 +1,5 @@ +APP = a +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/28_day/a/a.c b/28_day/a/a.c new file mode 100644 index 0000000..3df81f5 --- /dev/null +++ b/28_day/a/a.c @@ -0,0 +1,7 @@ +#include "apilib.h" + +void HariMain(void) +{ + api_putchar('A'); + api_end(); +} diff --git a/28_day/a/make.bat b/28_day/a/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/a/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/apilib.h b/28_day/apilib.h new file mode 100644 index 0000000..80ec6e0 --- /dev/null +++ b/28_day/apilib.h @@ -0,0 +1,20 @@ +void api_putchar(int c); +void api_putstr0(char *s); +void api_putstr1(char *s, int l); +void api_end(void); +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_free(char *addr, int size); +void api_point(int win, int x, int y, int col); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +void api_closewin(int win); +int api_getkey(int mode); +int api_alloctimer(void); +void api_inittimer(int timer, int data); +void api_settimer(int timer, int time); +void api_freetimer(int timer); +void api_beep(int tone); diff --git a/28_day/apilib/!cons_9x.bat b/28_day/apilib/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/apilib/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/apilib/!cons_nt.bat b/28_day/apilib/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/apilib/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/apilib/Makefile b/28_day/apilib/Makefile new file mode 100644 index 0000000..e93248b --- /dev/null +++ b/28_day/apilib/Makefile @@ -0,0 +1,47 @@ +OBJS_API = api001.obj api002.obj api003.obj api004.obj api005.obj api006.obj \ + api007.obj api008.obj api009.obj api010.obj api011.obj api012.obj \ + api013.obj api014.obj api015.obj api016.obj api017.obj api018.obj \ + api019.obj api020.obj + +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +# ftHg + +default : + $(MAKE) apilib.lib + +# t@CK + +apilib.lib : Makefile $(OBJS_API) + $(GOLIB) $(OBJS_API) out:apilib.lib + +# ʋK + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +# R}h + +clean : + -$(DEL) *.lst + -$(DEL) *.obj + +src_only : + $(MAKE) clean + -$(DEL) apilib.lib diff --git a/28_day/apilib/api001.nas b/28_day/apilib/api001.nas new file mode 100644 index 0000000..2f893a9 --- /dev/null +++ b/28_day/apilib/api001.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api001.nas"] + + GLOBAL _api_putchar + +[SECTION .text] + +_api_putchar: ; void api_putchar(int c); + MOV EDX,1 + MOV AL,[ESP+4] ; c + INT 0x40 + RET diff --git a/28_day/apilib/api002.nas b/28_day/apilib/api002.nas new file mode 100644 index 0000000..6ac9cc7 --- /dev/null +++ b/28_day/apilib/api002.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api002.nas"] + + GLOBAL _api_putstr0 + +[SECTION .text] + +_api_putstr0: ; void api_putstr0(char *s); + PUSH EBX + MOV EDX,2 + MOV EBX,[ESP+8] ; s + INT 0x40 + POP EBX + RET diff --git a/28_day/apilib/api003.nas b/28_day/apilib/api003.nas new file mode 100644 index 0000000..6c2d0fd --- /dev/null +++ b/28_day/apilib/api003.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api003.nas"] + + GLOBAL _api_putstr1 + +[SECTION .text] + +_api_putstr1: ; void api_putstr1(char *s, int l); + PUSH EBX + MOV EDX,3 + MOV EBX,[ESP+ 8] ; s + MOV ECX,[ESP+12] ; l + INT 0x40 + POP EBX + RET diff --git a/28_day/apilib/api004.nas b/28_day/apilib/api004.nas new file mode 100644 index 0000000..3c738a3 --- /dev/null +++ b/28_day/apilib/api004.nas @@ -0,0 +1,12 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api004.nas"] + + GLOBAL _api_end + +[SECTION .text] + +_api_end: ; void api_end(void); + MOV EDX,4 + INT 0x40 diff --git a/28_day/apilib/api005.nas b/28_day/apilib/api005.nas new file mode 100644 index 0000000..2157c61 --- /dev/null +++ b/28_day/apilib/api005.nas @@ -0,0 +1,24 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api005.nas"] + + GLOBAL _api_openwin + +[SECTION .text] + +_api_openwin: ; int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,5 + MOV EBX,[ESP+16] ; buf + MOV ESI,[ESP+20] ; xsiz + MOV EDI,[ESP+24] ; ysiz + MOV EAX,[ESP+28] ; col_inv + MOV ECX,[ESP+32] ; title + INT 0x40 + POP EBX + POP ESI + POP EDI + RET diff --git a/28_day/apilib/api006.nas b/28_day/apilib/api006.nas new file mode 100644 index 0000000..94cbb2d --- /dev/null +++ b/28_day/apilib/api006.nas @@ -0,0 +1,27 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api006.nas"] + + GLOBAL _api_putstrwin + +[SECTION .text] + +_api_putstrwin: ; void api_putstrwin(int win, int x, int y, int col, int len, char *str); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,6 + MOV EBX,[ESP+20] ; win + MOV ESI,[ESP+24] ; x + MOV EDI,[ESP+28] ; y + MOV EAX,[ESP+32] ; col + MOV ECX,[ESP+36] ; len + MOV EBP,[ESP+40] ; str + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET diff --git a/28_day/apilib/api007.nas b/28_day/apilib/api007.nas new file mode 100644 index 0000000..57be736 --- /dev/null +++ b/28_day/apilib/api007.nas @@ -0,0 +1,27 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api007.nas"] + + GLOBAL _api_boxfilwin + +[SECTION .text] + +_api_boxfilwin: ; void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,7 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET diff --git a/28_day/apilib/api008.nas b/28_day/apilib/api008.nas new file mode 100644 index 0000000..d1ed6c7 --- /dev/null +++ b/28_day/apilib/api008.nas @@ -0,0 +1,20 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api008.nas"] + + GLOBAL _api_initmalloc + +[SECTION .text] + +_api_initmalloc: ; void api_initmalloc(void); + PUSH EBX + MOV EDX,8 + MOV EBX,[CS:0x0020] ; malloc内存空间的地址 + MOV EAX,EBX + ADD EAX,32*1024 ; 加上32KB + MOV ECX,[CS:0x0000] ; 数据段的大小 + SUB ECX,EAX + INT 0x40 + POP EBX + RET diff --git a/28_day/apilib/api009.nas b/28_day/apilib/api009.nas new file mode 100644 index 0000000..bcd5307 --- /dev/null +++ b/28_day/apilib/api009.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api009.nas"] + + GLOBAL _api_malloc + +[SECTION .text] + +_api_malloc: ; char *api_malloc(int size); + PUSH EBX + MOV EDX,9 + MOV EBX,[CS:0x0020] + MOV ECX,[ESP+8] ; size + INT 0x40 + POP EBX + RET diff --git a/28_day/apilib/api010.nas b/28_day/apilib/api010.nas new file mode 100644 index 0000000..63a4ea5 --- /dev/null +++ b/28_day/apilib/api010.nas @@ -0,0 +1,18 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api010.nas"] + + GLOBAL _api_free + +[SECTION .text] + +_api_free: ; void api_free(char *addr, int size); + PUSH EBX + MOV EDX,10 + MOV EBX,[CS:0x0020] + MOV EAX,[ESP+ 8] ; addr + MOV ECX,[ESP+12] ; size + INT 0x40 + POP EBX + RET diff --git a/28_day/apilib/api011.nas b/28_day/apilib/api011.nas new file mode 100644 index 0000000..f5994b9 --- /dev/null +++ b/28_day/apilib/api011.nas @@ -0,0 +1,23 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api011.nas"] + + GLOBAL _api_point + +[SECTION .text] + +_api_point: ; void api_point(int win, int x, int y, int col); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,11 + MOV EBX,[ESP+16] ; win + MOV ESI,[ESP+20] ; x + MOV EDI,[ESP+24] ; y + MOV EAX,[ESP+28] ; col + INT 0x40 + POP EBX + POP ESI + POP EDI + RET diff --git a/28_day/apilib/api012.nas b/28_day/apilib/api012.nas new file mode 100644 index 0000000..9e9386f --- /dev/null +++ b/28_day/apilib/api012.nas @@ -0,0 +1,24 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api012.nas"] + + GLOBAL _api_refreshwin + +[SECTION .text] + +_api_refreshwin: ; void api_refreshwin(int win, int x0, int y0, int x1, int y1); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,12 + MOV EBX,[ESP+16] ; win + MOV EAX,[ESP+20] ; x0 + MOV ECX,[ESP+24] ; y0 + MOV ESI,[ESP+28] ; x1 + MOV EDI,[ESP+32] ; y1 + INT 0x40 + POP EBX + POP ESI + POP EDI + RET diff --git a/28_day/apilib/api013.nas b/28_day/apilib/api013.nas new file mode 100644 index 0000000..017f1ea --- /dev/null +++ b/28_day/apilib/api013.nas @@ -0,0 +1,27 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api013.nas"] + + GLOBAL _api_linewin + +[SECTION .text] + +_api_linewin: ; void api_linewin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,13 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET diff --git a/28_day/apilib/api014.nas b/28_day/apilib/api014.nas new file mode 100644 index 0000000..363db51 --- /dev/null +++ b/28_day/apilib/api014.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api014.nas"] + + GLOBAL _api_closewin + +[SECTION .text] + +_api_closewin: ; void api_closewin(int win); + PUSH EBX + MOV EDX,14 + MOV EBX,[ESP+8] ; win + INT 0x40 + POP EBX + RET diff --git a/28_day/apilib/api015.nas b/28_day/apilib/api015.nas new file mode 100644 index 0000000..bd27ec7 --- /dev/null +++ b/28_day/apilib/api015.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api015.nas"] + + GLOBAL _api_getkey + +[SECTION .text] + +_api_getkey: ; int api_getkey(int mode); + MOV EDX,15 + MOV EAX,[ESP+4] ; mode + INT 0x40 + RET diff --git a/28_day/apilib/api016.nas b/28_day/apilib/api016.nas new file mode 100644 index 0000000..e232412 --- /dev/null +++ b/28_day/apilib/api016.nas @@ -0,0 +1,13 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api016.nas"] + + GLOBAL _api_alloctimer + +[SECTION .text] + +_api_alloctimer: ; int api_alloctimer(void); + MOV EDX,16 + INT 0x40 + RET diff --git a/28_day/apilib/api017.nas b/28_day/apilib/api017.nas new file mode 100644 index 0000000..9e6a3cd --- /dev/null +++ b/28_day/apilib/api017.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api017.nas"] + + GLOBAL _api_inittimer + +[SECTION .text] + +_api_inittimer: ; void api_inittimer(int timer, int data); + PUSH EBX + MOV EDX,17 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; data + INT 0x40 + POP EBX + RET diff --git a/28_day/apilib/api018.nas b/28_day/apilib/api018.nas new file mode 100644 index 0000000..a91d6f1 --- /dev/null +++ b/28_day/apilib/api018.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api018.nas"] + + GLOBAL _api_settimer + +[SECTION .text] + +_api_settimer: ; void api_settimer(int timer, int time); + PUSH EBX + MOV EDX,18 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; time + INT 0x40 + POP EBX + RET diff --git a/28_day/apilib/api019.nas b/28_day/apilib/api019.nas new file mode 100644 index 0000000..d1c11e2 --- /dev/null +++ b/28_day/apilib/api019.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api019.nas"] + + GLOBAL _api_freetimer + +[SECTION .text] + +_api_freetimer: ; void api_freetimer(int timer); + PUSH EBX + MOV EDX,19 + MOV EBX,[ESP+ 8] ; timer + INT 0x40 + POP EBX + RET diff --git a/28_day/apilib/api020.nas b/28_day/apilib/api020.nas new file mode 100644 index 0000000..166bcda --- /dev/null +++ b/28_day/apilib/api020.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api020.nas"] + + GLOBAL _api_beep + +[SECTION .text] + +_api_beep: ; void api_beep(int tone); + MOV EDX,20 + MOV EAX,[ESP+4] ; tone + INT 0x40 + RET diff --git a/28_day/apilib/apilib.lib b/28_day/apilib/apilib.lib new file mode 100644 index 0000000000000000000000000000000000000000..29a8eeebd154eb753bb6d0e59a2125dff5d57df1 GIT binary patch literal 8966 zcmeI2&uv5w%5XY3zgzHW)jywS}zIi{^ zs~^`oyY){J*V10ed5ca-)fYK*TCxI?b?20d;e=|w_fW&6}na@=PnqsV7Bha zllH#Z`liuxcX5h4?T34frc-RR8rFkav)SI2z1`<~9n-YOXg6AxJnfiN-K{$VG#f3` zDeN}e-9hQDY27!!m6wTISd9m!{SkCHS})$E;`RZ|rK z#|@ljv<` zk{TKXJq@0(S4Kv|fTU3jLBsIt#Z#JokY1dkHm1RSlte+J&l|wuM!?oo)Fa?YdgWaq z5Jr@J91^)TiH%C^Mx_v|Uh=Q{?=)o4s((anyz1OXNffL8`Da^wa!*(bQavlP)H}#5 z_bQnc(ug!^#8=xvJ5)&zgy-*-cLjt;4X_o;1C=^a4ne2vx7mNteS+v*rZ%R-eUwB) z=hLk|d5(-{iSR5Fo)yBACOny5Gjo{`-413{)-&R#@Je)y7U@RHA0;cozPqG!{eMD< zcOXHjLX}Af!2ca!tG6Ds^wv0udn73()F@y8O#*o;b z_d>5k$H8&G?9V=eLYT<^1PVXU?+X7jr?#AXi()kkTw9nBbg=@*)j4->8D{hBcrR-3nB Wt<|Qd)cUcbwAxHvcu(R_7XJe03V>?> literal 0 HcmV?d00001 diff --git a/28_day/apilib/make.bat b/28_day/apilib/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/apilib/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/app_make.txt b/28_day/app_make.txt new file mode 100644 index 0000000..2bca4bc --- /dev/null +++ b/28_day/app_make.txt @@ -0,0 +1,79 @@ +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ +APILIBPATH = ../apilib/ +HARIBOTEPATH = ../haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -I../ -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) $(APP).hrb + +#文件生成规则 + +$(APP).bim : $(APP).obj $(APILIBPATH)apilib.lib Makefile ../app_make.txt + $(OBJ2BIM) @$(RULEFILE) out:$(APP).bim map:$(APP).map stack:$(STACK) \ + $(APP).obj $(APILIBPATH)apilib.lib + +$(APP).hrb : $(APP).bim Makefile ../app_make.txt + $(BIM2HRB) $(APP).bim $(APP).hrb $(MALLOC) + +haribote.img : ../haribote/ipl10.bin ../haribote/haribote.sys $(APP).hrb \ + Makefile ../app_make.txt + $(EDIMG) imgin:../../z_tools/fdimg0at.tek \ + wbinimg src:../haribote/ipl10.bin len:512 from:0 to:0 \ + copy from:../haribote/haribote.sys to:@: \ + copy from:$(APP).hrb to:@: \ + imgout:haribote.img + +#一般规则 + +%.gas : %.c ../apilib.h Makefile ../app_make.txt + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile ../app_make.txt + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile ../app_make.txt + $(NASK) $*.nas $*.obj $*.lst + +#命令 + +run : + $(MAKE) haribote.img + $(COPY) haribote.img ..\..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../../z_tools/qemu + +full : + $(MAKE) -C $(APILIBPATH) + $(MAKE) $(APP).hrb + +run_full : + $(MAKE) -C $(APILIBPATH) + $(MAKE) -C ../haribote + $(MAKE) run + +clean : + -$(DEL) *.lst + -$(DEL) *.obj + -$(DEL) *.map + -$(DEL) *.bim + -$(DEL) haribote.img + +src_only : + $(MAKE) clean + -$(DEL) $(APP).hrb diff --git a/28_day/beepdown/!cons_9x.bat b/28_day/beepdown/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/beepdown/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/beepdown/!cons_nt.bat b/28_day/beepdown/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/beepdown/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/beepdown/Makefile b/28_day/beepdown/Makefile new file mode 100644 index 0000000..ffd14fa --- /dev/null +++ b/28_day/beepdown/Makefile @@ -0,0 +1,5 @@ +APP = beepdown +STACK = 1k +MALLOC = 40k + +include ../app_make.txt diff --git a/28_day/beepdown/beepdown.c b/28_day/beepdown/beepdown.c new file mode 100644 index 0000000..d08962c --- /dev/null +++ b/28_day/beepdown/beepdown.c @@ -0,0 +1,19 @@ +#include "apilib.h" + +void HariMain(void) +{ + int i, timer; + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (i = 20000000; i >= 20000; i -= i / 100) { + /* 20KHz~20Hz,即人类可以听到的声音范围*/ + /* i以1%的速度递减*/ + api_beep(i); + api_settimer(timer, 1); /* 0.01秒*/ + if (api_getkey(1) != 128) { + break; + } + } + api_beep(0); + api_end(); +} diff --git a/28_day/beepdown/make.bat b/28_day/beepdown/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/beepdown/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/color/!cons_9x.bat b/28_day/color/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/color/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/color/!cons_nt.bat b/28_day/color/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/color/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/color/Makefile b/28_day/color/Makefile new file mode 100644 index 0000000..614dac9 --- /dev/null +++ b/28_day/color/Makefile @@ -0,0 +1,5 @@ +APP = color +STACK = 1k +MALLOC = 56k + +include ../app_make.txt diff --git a/28_day/color/color.c b/28_day/color/color.c new file mode 100644 index 0000000..ce228e2 --- /dev/null +++ b/28_day/color/color.c @@ -0,0 +1,21 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win, x, y, r, g, b; + api_initmalloc(); + buf = api_malloc(144 * 164); + win = api_openwin(buf, 144, 164, -1, "color"); + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) { + r = x * 2; + g = y * 2; + b = 0; + buf[(x + 8) + (y + 28) * 144] = 16 + (r / 43) + (g / 43) * 6 + (b / 43) * 36; + } + } + api_refreshwin(win, 8, 28, 136, 156); + api_getkey(1); /*等待按下任意键*/ + api_end(); +} diff --git a/28_day/color/make.bat b/28_day/color/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/color/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/color2/!cons_9x.bat b/28_day/color2/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/color2/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/color2/!cons_nt.bat b/28_day/color2/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/color2/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/color2/Makefile b/28_day/color2/Makefile new file mode 100644 index 0000000..93b5f23 --- /dev/null +++ b/28_day/color2/Makefile @@ -0,0 +1,5 @@ +APP = color2 +STACK = 1k +MALLOC = 56k + +include ../app_make.txt diff --git a/28_day/color2/color2.c b/28_day/color2/color2.c new file mode 100644 index 0000000..82e3f6a --- /dev/null +++ b/28_day/color2/color2.c @@ -0,0 +1,36 @@ +#include "apilib.h" + +unsigned char rgb2pal(int r, int g, int b, int x, int y); + +void HariMain(void) +{ + char *buf; + int win, x, y; + api_initmalloc(); + buf = api_malloc(144 * 164); + win = api_openwin(buf, 144, 164, -1, "color2"); + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) { + buf[(x + 8) + (y + 28) * 144] = rgb2pal(x * 2, y * 2, 0, x, y); + } + } + api_refreshwin(win, 8, 28, 136, 156); + api_getkey(1); /* �Ă��Ƃ��ȃL�[���͂�҂� */ + api_end(); +} + +unsigned char rgb2pal(int r, int g, int b, int x, int y) +{ + static int table[4] = { 3, 1, 0, 2 }; + int i; + x &= 1; /*判断是偶数还是奇数*/ + y &= 1; + i = table[x + y * 2]; /*用来生成中间色的常量*/ + r = (r * 21) / 256; /* r为0~20*/ + g = (g * 21) / 256; + b = (b * 21) / 256; + r = (r + i) / 4; /* r为0~5*/ + g = (g + i) / 4; + b = (b + i) / 4; + return 16 + r + g * 6 + b * 36; +} diff --git a/28_day/color2/make.bat b/28_day/color2/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/color2/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/haribote.rul b/28_day/haribote.rul new file mode 100644 index 0000000..ee8f67b --- /dev/null +++ b/28_day/haribote.rul @@ -0,0 +1,10 @@ +format: + code(align:1, logic:0x24, file:0x24); + data(align:4, logic:stack_end, file:code_end); + +file: + ../../z_tools/haribote/harilibc.lib; + ../../z_tools/haribote/golibc.lib; + +label: + _HariStartup; diff --git a/28_day/haribote/!cons_9x.bat b/28_day/haribote/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/haribote/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/haribote/!cons_nt.bat b/28_day/haribote/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/haribote/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/haribote/Makefile b/28_day/haribote/Makefile new file mode 100644 index 0000000..b0ce461 --- /dev/null +++ b/28_day/haribote/Makefile @@ -0,0 +1,79 @@ +OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \ + int.obj fifo.obj keyboard.obj mouse.obj memory.obj sheet.obj timer.obj \ + mtask.obj window.obj console.obj file.obj + +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) ipl10.bin + $(MAKE) haribote.sys + +# 镜像文件生成 + +ipl10.bin : ipl10.nas Makefile + $(NASK) ipl10.nas ipl10.bin ipl10.lst + +asmhead.bin : asmhead.nas Makefile + $(NASK) asmhead.nas asmhead.bin asmhead.lst + +hankaku.bin : hankaku.txt Makefile + $(MAKEFONT) hankaku.txt hankaku.bin + +hankaku.obj : hankaku.bin Makefile + $(BIN2OBJ) hankaku.bin hankaku.obj _hankaku + +bootpack.bim : $(OBJS_BOOTPACK) Makefile + $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \ + $(OBJS_BOOTPACK) +# 3MB+64KB=3136KB + +bootpack.hrb : bootpack.bim Makefile + $(BIM2HRB) bootpack.bim bootpack.hrb 0 + +haribote.sys : asmhead.bin bootpack.hrb Makefile + copy /B asmhead.bin+bootpack.hrb haribote.sys + +# 其他指令 + +%.gas : %.c bootpack.h Makefile + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +# 运行程序 + +clean : + -$(DEL) asmhead.bin + -$(DEL) hankaku.bin + -$(DEL) *.lst + -$(DEL) *.obj + -$(DEL) *.map + -$(DEL) *.bim + -$(DEL) *.hrb + +src_only : + $(MAKE) clean + -$(DEL) ipl10.bin + -$(DEL) haribote.sys diff --git a/28_day/haribote/asmhead.nas b/28_day/haribote/asmhead.nas new file mode 100644 index 0000000..ad35d76 --- /dev/null +++ b/28_day/haribote/asmhead.nas @@ -0,0 +1,202 @@ +; haribote-os boot asm +; TAB=4 + +[INSTRSET "i486p"] + +VBEMODE EQU 0x105 ; 1024 x 768 x 8bit 彩色 +; 显示模式 +; 0x100 : 640 x 400 x 8bit 彩色 +; 0x101 : 640 x 480 x 8bit 彩色 +; 0x103 : 800 x 600 x 8bit 彩色 +; 0x105 : 1024 x 768 x 8bit 彩色 +; 0x107 : 1280 x 1024 x 8bit 彩色 + +BOTPAK EQU 0x00280000 ; 加载bootpack +DSKCAC EQU 0x00100000 ; 磁盘缓存的位置 +DSKCAC0 EQU 0x00008000 ; 磁盘缓存的位置(实模式) + +; BOOT_INFO 相关 +CYLS EQU 0x0ff0 ; 引导扇区设置 +LEDS EQU 0x0ff1 +VMODE EQU 0x0ff2 ; 关于颜色的信息 +SCRNX EQU 0x0ff4 ; 分辨率X +SCRNY EQU 0x0ff6 ; 分辨率Y +VRAM EQU 0x0ff8 ; 图像缓冲区的起始地址 + + ORG 0xc200 ; 这个的程序要被装载的内存地址 + +; 确认VBE是否存在 + + MOV AX,0x9000 + MOV ES,AX + MOV DI,0 + MOV AX,0x4f00 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 检查VBE的版本 + + MOV AX,[ES:DI+4] + CMP AX,0x0200 + JB scrn320 ; if (AX < 0x0200) goto scrn320 + +; 取得画面模式信息 + + MOV CX,VBEMODE + MOV AX,0x4f01 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 画面模式信息的确认 + CMP BYTE [ES:DI+0x19],8 ;颜色数必须为8 + JNE scrn320 + CMP BYTE [ES:DI+0x1b],4 ;颜色的指定方法必须为4(4是调色板模式) + JNE scrn320 + MOV AX,[ES:DI+0x00] ;模式属性bit7不是1就不能加上0x4000 + AND AX,0x0080 + JZ scrn320 ; 模式属性的bit7是0,所以放弃 + +; 画面设置 + + MOV BX,VBEMODE+0x4000 + MOV AX,0x4f02 + INT 0x10 + MOV BYTE [VMODE],8 ; 屏幕的模式(参考C语言的引用) + MOV AX,[ES:DI+0x12] + MOV [SCRNX],AX + MOV AX,[ES:DI+0x14] + MOV [SCRNY],AX + MOV EAX,[ES:DI+0x28] ;VRAM的地址 + MOV [VRAM],EAX + JMP keystatus + +scrn320: + MOV AL,0x13 ; VGA图、320x200x8bit彩色 + MOV AH,0x00 + INT 0x10 + MOV BYTE [VMODE],8 ; 记下画面模式(参考C语言) + MOV WORD [SCRNX],320 + MOV WORD [SCRNY],200 + MOV DWORD [VRAM],0x000a0000 + +; 通过 BIOS 获取指示灯状态 + +keystatus: + MOV AH,0x02 + INT 0x16 ; keyboard BIOS + MOV [LEDS],AL + +; PIC关闭一切中断 +; 根据AT兼容机的规格,如果要初始化PIC, +; 必须在CLI之前进行,否则有时会挂起。 +; 随后进行PIC的初始化。 + + MOV AL,0xff + OUT 0x21,AL + NOP ; 如果连续执行OUT指令,有些机种会无法正常运行 + OUT 0xa1,AL + + CLI ; 禁止CPU级别的中断 + +; 为了让CPU能够访问1MB以上的内存空间,设定A20GATE + + CALL waitkbdout + MOV AL,0xd1 + OUT 0x64,AL + CALL waitkbdout + MOV AL,0xdf ; enable A20 + OUT 0x60,AL + CALL waitkbdout + +; 切换到保护模式 + +[INSTRSET "i486p"] ; 说明使用486指令 + + LGDT [GDTR0] ; 设置临时GDT + MOV EAX,CR0 + AND EAX,0x7fffffff ; 设bit31为0(禁用分页) + OR EAX,0x00000001 ; bit0到1转换(保护模式过渡) + MOV CR0,EAX + JMP pipelineflush +pipelineflush: + MOV AX,1*8 ; 可读写的段 32bit + MOV DS,AX + MOV ES,AX + MOV FS,AX + MOV GS,AX + MOV SS,AX + +; bootpack传递 + + MOV ESI,bootpack ; 转送源 + MOV EDI,BOTPAK ; 转送目标 + MOV ECX,512*1024/4 + CALL memcpy + +; 磁盘数据最终转送到它本来的位置去 +; 首先从启动扇区开始 + + MOV ESI,0x7c00 ; 转送源 + MOV EDI,DSKCAC ; 转送目标 + MOV ECX,512/4 + CALL memcpy + +; 剩余的全部 + + MOV ESI,DSKCAC0+512 ; 转送源 + MOV EDI,DSKCAC+512 ; 转送源目标 + MOV ECX,0 + MOV CL,BYTE [CYLS] + IMUL ECX,512*18*2/4 ; 从柱面数变换为字节数/4 + SUB ECX,512/4 ; 减去 IPL 偏移量 + CALL memcpy + +; 必须由asmhead来完成的工作,至此全部完毕 +; 以后就交由bootpack来完成 + +; bootpack启动 + + MOV EBX,BOTPAK + MOV ECX,[EBX+16] + ADD ECX,3 ; ECX += 3; + SHR ECX,2 ; ECX /= 4; + JZ skip ; 没有要转送的东西时 + MOV ESI,[EBX+20] ; 转送源 + ADD ESI,EBX + MOV EDI,[EBX+12] ; 转送目标 + CALL memcpy +skip: + MOV ESP,[EBX+12] ; 堆栈的初始化 + JMP DWORD 2*8:0x0000001b + +waitkbdout: + IN AL,0x64 + AND AL,0x02 + JNZ waitkbdout ; AND的结果如果不是0,就跳到waitkbdout + RET + +memcpy: + MOV EAX,[ESI] + ADD ESI,4 + MOV [EDI],EAX + ADD EDI,4 + SUB ECX,1 + JNZ memcpy ; 减法运算的结果如果不是0,就跳转到memcpy + RET +; memcpy地址前缀大小 + + ALIGNB 16 +GDT0: + RESB 8 ; 初始值 + DW 0xffff,0x0000,0x9200,0x00cf ; 可以读写的段(segment)32bit + DW 0xffff,0x0000,0x9a28,0x0047 ; 可执行的文件的32bit寄存器(bootpack用) + + DW 0 +GDTR0: + DW 8*3-1 + DD GDT0 + + ALIGNB 16 +bootpack: diff --git a/28_day/haribote/bootpack.c b/28_day/haribote/bootpack.c new file mode 100644 index 0000000..d4f821a --- /dev/null +++ b/28_day/haribote/bootpack.c @@ -0,0 +1,387 @@ +/* bootpack */ + +#include "bootpack.h" +#include + +#define KEYCMD_LED 0xed + +void keywin_off(struct SHEET *key_win); +void keywin_on(struct SHEET *key_win); +void close_console(struct SHEET *sht); +void close_constask(struct TASK *task); + +void HariMain(void) +{ + struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; + struct SHTCTL *shtctl; + char s[40]; + struct FIFO32 fifo, keycmd; + int fifobuf[128], keycmd_buf[32]; + int mx, my, i, new_mx = -1, new_my = 0, new_wx = 0x7fffffff, new_wy = 0; + unsigned int memtotal; + struct MOUSE_DEC mdec; + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + unsigned char *buf_back, buf_mouse[256]; + struct SHEET *sht_back, *sht_mouse; + struct TASK *task_a, *task; + static char keytable0[0x80] = { + 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0x08, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0x0a, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0 + }; + static char keytable1[0x80] = { + 0, 0, '!', 0x22, '#', '$', '%', '&', 0x27, '(', ')', '~', '=', '~', 0x08, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0x0a, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', '+', '*', 0, 0, '}', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, '|', 0, 0 + }; + int key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; + int j, x, y, mmx = -1, mmy = -1, mmx2 = 0; + struct SHEET *sht = 0, *key_win, *sht2; + + init_gdtidt(); + init_pic(); + io_sti(); /* IDT/PIC的初始化已经完成,于是开放CPU的中断 */ + fifo32_init(&fifo, 128, fifobuf, 0); + *((int *) 0x0fec) = (int) &fifo; + init_pit(); + init_keyboard(&fifo, 256); + enable_mouse(&fifo, 512, &mdec); + io_out8(PIC0_IMR, 0xf8); /* 设定PIT和PIC1以及键盘为许可(11111000) */ + io_out8(PIC1_IMR, 0xef); /* 开放鼠标中断(11101111) */ + fifo32_init(&keycmd, 32, keycmd_buf, 0); + + memtotal = memtest(0x00400000, 0xbfffffff); + memman_init(memman); + memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */ + memman_free(memman, 0x00400000, memtotal - 0x00400000); + + init_palette(); + shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny); + task_a = task_init(memman); + fifo.task = task_a; + task_run(task_a, 1, 2); + *((int *) 0x0fe4) = (int) shtctl; + + /* sht_back */ + sht_back = sheet_alloc(shtctl); + buf_back = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny); + sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 无透明色 */ + init_screen8(buf_back, binfo->scrnx, binfo->scrny); + + /* sht_cons */ + key_win = open_console(shtctl, memtotal); + + /* sht_mouse */ + sht_mouse = sheet_alloc(shtctl); + sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99); + init_mouse_cursor8(buf_mouse, 99); + mx = (binfo->scrnx - 16) / 2; /* 计算坐标使其位于画面中央 */ + my = (binfo->scrny - 28 - 16) / 2; + + sheet_slide(sht_back, 0, 0); + sheet_slide(key_win, 32, 4); + sheet_slide(sht_mouse, mx, my); + sheet_updown(sht_back, 0); + sheet_updown(key_win, 1); + sheet_updown(sht_mouse, 2); + keywin_on(key_win); + + /*为了避免和键盘当前状态冲突,在一开始先进行设置*/ + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + + for (;;) { + if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0) { + /* 如果存在向键盘控制器发送的数据,则发送它 */ + keycmd_wait = fifo32_get(&keycmd); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + io_cli(); + if (fifo32_status(&fifo) == 0) { + /* FIFO为空,当存在搁置的绘图操作时立即执行*/ + if (new_mx >= 0) { + io_sti(); + sheet_slide(sht_mouse, new_mx, new_my); + new_mx = -1; + } else if (new_wx != 0x7fffffff) { + io_sti(); + sheet_slide(sht, new_wx, new_wy); + new_wx = 0x7fffffff; + } else { + task_sleep(task_a); + io_sti(); + } + } else { + i = fifo32_get(&fifo); + io_sti(); + if (key_win != 0 && key_win->flags == 0) { /*窗口被关闭*/ + if (shtctl->top == 1) { /*当画面上只剩鼠标和背景时*/ + key_win = 0; + } else { + key_win = shtctl->sheets[shtctl->top - 1]; + keywin_on(key_win); + } + } + if (256 <= i && i <= 511) { /* 键盘数据*/ + if (i < 0x80 + 256) { /*将按键编码转换为字符编码*/ + if (key_shift == 0) { + s[0] = keytable0[i - 256]; + } else { + s[0] = keytable1[i - 256]; + } + } else { + s[0] = 0; + } + if ('A' <= s[0] && s[0] <= 'Z') { /*当输入字符为英文字母时*/ + if (((key_leds & 4) == 0 && key_shift == 0) || + ((key_leds & 4) != 0 && key_shift != 0)) { + s[0] += 0x20; /*将大写字母转换为小写字母*/ + } + } + if (s[0] != 0 && key_win != 0) { /*一般字符、退格键、回车键*/ + fifo32_put(&key_win->task->fifo, s[0] + 256); + } + if (i == 256 + 0x0f && key_win != 0) { /* Tab键 */ + keywin_off(key_win); + j = key_win->height - 1; + if (j == 0) { + j = shtctl->top - 1; + } + key_win = shtctl->sheets[j]; + keywin_on(key_win); + } + if (i == 256 + 0x2a) { /*左Shift ON */ + key_shift |= 1; + } + if (i == 256 + 0x36) { /*右Shift ON */ + key_shift |= 2; + } + if (i == 256 + 0xaa) { /*左Shift OFF */ + key_shift &= ~1; + } + if (i == 256 + 0xb6) { /*右Shift OFF */ + key_shift &= ~2; + } + if (i == 256 + 0x3a) { /* CapsLock */ + key_leds ^= 4; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x45) { /* NumLock */ + key_leds ^= 2; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x46) { /* ScrollLock */ + key_leds ^= 1; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x3b && key_shift != 0 && key_win != 0) { /* Shift+F1 */ + task = key_win->task; + if (task != 0 && task->tss.ss0 != 0) { + cons_putstr0(task->cons, "\nBreak(key) :\n"); + io_cli(); /*强制结束处理时禁止任务切换*/ + task->tss.eax = (int) &(task->tss.esp0); + task->tss.eip = (int) asm_end_app; + io_sti(); + task_run(task, -1, 0); /*为了确实执行结束处理,如果处于休眠状态则唤醒*/ + } + } + if (i == 256 + 0x3c && key_shift != 0) { /* Shift+F2 */ + if (key_win != 0) { + keywin_off(key_win); + } + key_win = open_console(shtctl, memtotal); + sheet_slide(key_win, 32, 4); + sheet_updown(key_win, shtctl->top); + keywin_on(key_win); + } + if (i == 256 + 0x57) { /* F11 */ + sheet_updown(shtctl->sheets[1], shtctl->top - 1); + } + if (i == 256 + 0xfa) { /*键盘成功接收到数据*/ + keycmd_wait = -1; + } + if (i == 256 + 0xfe) { /*键盘没有成功接收到数据*/ + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + } else if (512 <= i && i <= 767) { /* 鼠标数据*/ + if (mouse_decode(&mdec, i - 512) != 0) { + /* 已经收集了3字节的数据,移动光标 */ + mx += mdec.x; + my += mdec.y; + if (mx < 0) { + mx = 0; + } + if (my < 0) { + my = 0; + } + if (mx > binfo->scrnx - 1) { + mx = binfo->scrnx - 1; + } + if (my > binfo->scrny - 1) { + my = binfo->scrny - 1; + } + new_mx = mx; + new_my = my; + if ((mdec.btn & 0x01) != 0) { /* 按下左键 */ + if (mmx < 0) { + /*如果处于通常模式*/ + /*按照从上到下的顺序寻找鼠标所指向的图层*/ + for (j = shtctl->top - 1; j > 0; j--) { + sht = shtctl->sheets[j]; + x = mx - sht->vx0; + y = my - sht->vy0; + if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) { + if (sht->buf[y * sht->bxsize + x] != sht->col_inv) { + sheet_updown(sht, shtctl->top - 1); + if (sht != key_win) { + keywin_off(key_win); + key_win = sht; + keywin_on(key_win); + } + if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) { + mmx = mx; /*进入窗口移动模式*/ + mmy = my; + mmx2 = sht->vx0; + new_wy = sht->vy0; + } + if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <= y && y < 19) { + /*点击“×”按钮*/ + if ((sht->flags & 0x10) != 0) { /*该窗口是否为应用程序窗口?*/ + task = sht->task; + cons_putstr0(task->cons, "\nBreak(mouse) :\n"); + io_cli(); /*强制结束处理时禁止任务切换*/ + task->tss.eax = (int) &(task->tss.esp0); + task->tss.eip = (int) asm_end_app; + io_sti(); + task_run(task, -1, 0); + } else { /*命令行窗口*/ + task = sht->task; + sheet_updown(sht, -1); /*暂且隐藏该图层*/ + keywin_off(key_win); + key_win = shtctl->sheets[shtctl->top - 1]; + keywin_on(key_win); + io_cli(); + fifo32_put(&task->fifo, 4); + io_sti(); + } + } + break; + } + } + } + } else { + /*如果处于窗口移动模式*/ + x = mx - mmx; /*计算鼠标指针移动量*/ + y = my - mmy; + new_wx = (mmx2 + x + 2) & ~3; + new_wy = new_wy + y; + mmy = my; + } + } else { + /*没有按下左键*/ + mmx = -1; /*切换到一般模式*/ + if (new_wx != 0x7fffffff) { + sheet_slide(sht, new_wx, new_wy); /*固定图层位置*/ + new_wx = 0x7fffffff; + } + } + } + } else if (768 <= i && i <= 1023) { /*命令行窗口关闭处理*/ + close_console(shtctl->sheets0 + (i - 768)); + } else if (1024 <= i && i <= 2023) { + close_constask(taskctl->tasks0 + (i - 1024)); + } else if (2024 <= i && i <= 2279) { /*只关闭命令行窗口*/ + sht2 = shtctl->sheets0 + (i - 2024); + memman_free_4k(memman, (int) sht2->buf, 256 * 165); + sheet_free(sht2); + } + } + } +} + +void keywin_off(struct SHEET *key_win) +{ + change_wtitle8(key_win, 0); + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 3); /*命令行窗口光标OFF */ + } + return; +} + +void keywin_on(struct SHEET *key_win) +{ + change_wtitle8(key_win, 1); + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 2); /*命令行窗口光标ON */ + } + return; +} + +struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = task_alloc(); + int *cons_fifo = (int *) memman_alloc_4k(memman, 128 * 4); + task->cons_stack = memman_alloc_4k(memman, 64 * 1024); + task->tss.esp = task->cons_stack + 64 * 1024 - 12; + task->tss.eip = (int) &console_task; + task->tss.es = 1 * 8; + task->tss.cs = 2 * 8; + task->tss.ss = 1 * 8; + task->tss.ds = 1 * 8; + task->tss.fs = 1 * 8; + task->tss.gs = 1 * 8; + *((int *) (task->tss.esp + 4)) = (int) sht; + *((int *) (task->tss.esp + 8)) = memtotal; + task_run(task, 2, 2); /* level=2, priority=2 */ + fifo32_init(&task->fifo, 128, cons_fifo, task); + return task; +} + +struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct SHEET *sht = sheet_alloc(shtctl); + unsigned char *buf = (unsigned char *) memman_alloc_4k(memman, 256 * 165); + sheet_setbuf(sht, buf, 256, 165, -1); /*无透明色*/ + make_window8(buf, 256, 165, "console", 0); + make_textbox8(sht, 8, 28, 240, 128, COL8_000000); + sht->task = open_constask(sht, memtotal); + sht->flags |= 0x20; /*有光标*/ + return sht; +} + +void close_constask(struct TASK *task) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + task_sleep(task); + memman_free_4k(memman, task->cons_stack, 64 * 1024); + memman_free_4k(memman, (int) task->fifo.buf, 128 * 4); + task->flags = 0; /*用来替代task_free(task); */ + return; +} + +void close_console(struct SHEET *sht) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = sht->task; + memman_free_4k(memman, (int) sht->buf, 256 * 165); + sheet_free(sht); + close_constask(task); + return; +} diff --git a/28_day/haribote/bootpack.h b/28_day/haribote/bootpack.h new file mode 100644 index 0000000..f4ec328 --- /dev/null +++ b/28_day/haribote/bootpack.h @@ -0,0 +1,283 @@ +/* asmhead.nas */ +struct BOOTINFO { /* 0x0ff0-0x0fff */ + char cyls; /* 启动区读磁盘读到此为止 */ + char leds; /* 启动时键盘的LED的状态 */ + char vmode; /* 显卡模式为多少位彩色 */ + char reserve; + short scrnx, scrny; /* 画面分辨率 */ + char *vram; +}; +#define ADR_BOOTINFO 0x00000ff0 +#define ADR_DISKIMG 0x00100000 + +/* naskfunc.nas */ +void io_hlt(void); +void io_cli(void); +void io_sti(void); +void io_stihlt(void); +int io_in8(int port); +void io_out8(int port, int data); +int io_load_eflags(void); +void io_store_eflags(int eflags); +void load_gdtr(int limit, int addr); +void load_idtr(int limit, int addr); +int load_cr0(void); +void store_cr0(int cr0); +void load_tr(int tr); +void asm_inthandler0c(void); +void asm_inthandler0d(void); +void asm_inthandler20(void); +void asm_inthandler21(void); +void asm_inthandler2c(void); +unsigned int memtest_sub(unsigned int start, unsigned int end); +void farjmp(int eip, int cs); +void farcall(int eip, int cs); +void asm_hrb_api(void); +void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); +void asm_end_app(void); + +/* fifo.c */ +struct FIFO32 { + int *buf; + int p, q, size, free, flags; + struct TASK *task; +}; +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task); +int fifo32_put(struct FIFO32 *fifo, int data); +int fifo32_get(struct FIFO32 *fifo); +int fifo32_status(struct FIFO32 *fifo); + +/* graphic.c */ +void init_palette(void); +void set_palette(int start, int end, unsigned char *rgb); +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); +void init_screen8(char *vram, int x, int y); +void putfont8(char *vram, int xsize, int x, int y, char c, char *font); +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s); +void init_mouse_cursor8(char *mouse, char bc); +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize); +#define COL8_000000 0 +#define COL8_FF0000 1 +#define COL8_00FF00 2 +#define COL8_FFFF00 3 +#define COL8_0000FF 4 +#define COL8_FF00FF 5 +#define COL8_00FFFF 6 +#define COL8_FFFFFF 7 +#define COL8_C6C6C6 8 +#define COL8_840000 9 +#define COL8_008400 10 +#define COL8_848400 11 +#define COL8_000084 12 +#define COL8_840084 13 +#define COL8_008484 14 +#define COL8_848484 15 + +/* dsctbl.c */ +struct SEGMENT_DESCRIPTOR { + short limit_low, base_low; + char base_mid, access_right; + char limit_high, base_high; +}; +struct GATE_DESCRIPTOR { + short offset_low, selector; + char dw_count, access_right; + short offset_high; +}; +void init_gdtidt(void); +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar); +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar); +#define ADR_IDT 0x0026f800 +#define LIMIT_IDT 0x000007ff +#define ADR_GDT 0x00270000 +#define LIMIT_GDT 0x0000ffff +#define ADR_BOTPAK 0x00280000 +#define LIMIT_BOTPAK 0x0007ffff +#define AR_DATA32_RW 0x4092 +#define AR_CODE32_ER 0x409a +#define AR_LDT 0x0082 +#define AR_TSS32 0x0089 +#define AR_INTGATE32 0x008e + +/* int.c */ +void init_pic(void); +#define PIC0_ICW1 0x0020 +#define PIC0_OCW2 0x0020 +#define PIC0_IMR 0x0021 +#define PIC0_ICW2 0x0021 +#define PIC0_ICW3 0x0021 +#define PIC0_ICW4 0x0021 +#define PIC1_ICW1 0x00a0 +#define PIC1_OCW2 0x00a0 +#define PIC1_IMR 0x00a1 +#define PIC1_ICW2 0x00a1 +#define PIC1_ICW3 0x00a1 +#define PIC1_ICW4 0x00a1 + +/* keyboard.c */ +void inthandler21(int *esp); +void wait_KBC_sendready(void); +void init_keyboard(struct FIFO32 *fifo, int data0); +#define PORT_KEYDAT 0x0060 +#define PORT_KEYCMD 0x0064 + +/* mouse.c */ +struct MOUSE_DEC { + unsigned char buf[3], phase; + int x, y, btn; +}; +void inthandler2c(int *esp); +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec); +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat); + +/* memory.c */ +#define MEMMAN_FREES 4090 /* ����Ŗ�32KB */ +#define MEMMAN_ADDR 0x003c0000 +struct FREEINFO { /* ������� */ + unsigned int addr, size; +}; +struct MEMMAN { /* �������Ǘ� */ + int frees, maxfrees, lostsize, losts; + struct FREEINFO free[MEMMAN_FREES]; +}; +unsigned int memtest(unsigned int start, unsigned int end); +void memman_init(struct MEMMAN *man); +unsigned int memman_total(struct MEMMAN *man); +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size); +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size); +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size); +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size); + +/* sheet.c */ +#define MAX_SHEETS 256 +struct SHEET { + unsigned char *buf; + int bxsize, bysize, vx0, vy0, col_inv, height, flags; + struct SHTCTL *ctl; + struct TASK *task; +}; +struct SHTCTL { + unsigned char *vram, *map; + int xsize, ysize, top; + struct SHEET *sheets[MAX_SHEETS]; + struct SHEET sheets0[MAX_SHEETS]; +}; +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize); +struct SHEET *sheet_alloc(struct SHTCTL *ctl); +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv); +void sheet_updown(struct SHEET *sht, int height); +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1); +void sheet_slide(struct SHEET *sht, int vx0, int vy0); +void sheet_free(struct SHEET *sht); + +/* timer.c */ +#define MAX_TIMER 500 +struct TIMER { + struct TIMER *next; + unsigned int timeout; + char flags, flags2; + struct FIFO32 *fifo; + int data; +}; +struct TIMERCTL { + unsigned int count, next; + struct TIMER *t0; + struct TIMER timers0[MAX_TIMER]; +}; +extern struct TIMERCTL timerctl; +void init_pit(void); +struct TIMER *timer_alloc(void); +void timer_free(struct TIMER *timer); +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data); +void timer_settime(struct TIMER *timer, unsigned int timeout); +void inthandler20(int *esp); +int timer_cancel(struct TIMER *timer); +void timer_cancelall(struct FIFO32 *fifo); + +/* mtask.c */ +#define MAX_TASKS 1000 /*最大任务数量*/ +#define TASK_GDT0 3 /*定义从GDT的几号开始分配给TSS */ +#define MAX_TASKS_LV 100 +#define MAX_TASKLEVELS 10 +struct TSS32 { + int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3; + int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi; + int es, cs, ss, ds, fs, gs; + int ldtr, iomap; +}; +struct TASK { + int sel, flags; /* sel用来存放GDT的编号*/ + int level, priority; /* 优先级 */ + struct FIFO32 fifo; + struct TSS32 tss; + struct SEGMENT_DESCRIPTOR ldt[2]; + struct CONSOLE *cons; + int ds_base, cons_stack; +}; +struct TASKLEVEL { + int running; /*正在运行的任务数量*/ + int now; /*这个变量用来记录当前正在运行的是哪个任务*/ + struct TASK *tasks[MAX_TASKS_LV]; +}; +struct TASKCTL { + int now_lv; /*现在活动中的LEVEL */ + char lv_change; /*在下次任务切换时是否需要改变LEVEL */ + struct TASKLEVEL level[MAX_TASKLEVELS]; + struct TASK tasks0[MAX_TASKS]; +}; +extern struct TASKCTL *taskctl; +extern struct TIMER *task_timer; +struct TASK *task_now(void); +struct TASK *task_init(struct MEMMAN *memman); +struct TASK *task_alloc(void); +void task_run(struct TASK *task, int level, int priority); +void task_switch(void); +void task_sleep(struct TASK *task); + +/* window.c */ +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act); +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l); +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c); +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act); +void change_wtitle8(struct SHEET *sht, char act); + +/* console.c */ +struct CONSOLE { + struct SHEET *sht; + int cur_x, cur_y, cur_c; + struct TIMER *timer; +}; +void console_task(struct SHEET *sheet, int memtotal); +void cons_putchar(struct CONSOLE *cons, int chr, char move); +void cons_newline(struct CONSOLE *cons); +void cons_putstr0(struct CONSOLE *cons, char *s); +void cons_putstr1(struct CONSOLE *cons, char *s, int l); +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal); +void cmd_mem(struct CONSOLE *cons, int memtotal); +void cmd_cls(struct CONSOLE *cons); +void cmd_dir(struct CONSOLE *cons); +void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline); +void cmd_exit(struct CONSOLE *cons, int *fat); +void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal); +void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal); +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline); +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax); +int *inthandler0d(int *esp); +int *inthandler0c(int *esp); +void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col); + +/* file.c */ +struct FILEINFO { + unsigned char name[8], ext[3], type; + char reserve[10]; + unsigned short time, date, clustno; + unsigned int size; +}; +void file_readfat(int *fat, unsigned char *img); +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img); +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max); + +/* bootpack.c */ +struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal); +struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal); diff --git a/28_day/haribote/console.c b/28_day/haribote/console.c new file mode 100644 index 0000000..6ce8fdc --- /dev/null +++ b/28_day/haribote/console.c @@ -0,0 +1,604 @@ +/* 命令行窗口相关 */ + +#include "bootpack.h" +#include +#include + +void console_task(struct SHEET *sheet, int memtotal) +{ + struct TASK *task = task_now(); + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + int i, *fat = (int *) memman_alloc_4k(memman, 4 * 2880); + struct CONSOLE cons; + char cmdline[30]; + cons.sht = sheet; + cons.cur_x = 8; + cons.cur_y = 28; + cons.cur_c = -1; + task->cons = &cons; + + if (cons.sht != 0) { + cons.timer = timer_alloc(); + timer_init(cons.timer, &task->fifo, 1); + timer_settime(cons.timer, 50); + } + file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); + + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + task_sleep(task); + io_sti(); + } else { + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1 && cons.sht != 0) { /*光标用定时器*/ + if (i != 0) { + timer_init(cons.timer, &task->fifo, 0); /*下次置0 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_FFFFFF; + } + } else { + timer_init(cons.timer, &task->fifo, 1); /*下次置1 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_000000; + } + } + timer_settime(cons.timer, 50); + } + if (i == 2) { /*光标ON */ + cons.cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + if (cons.sht != 0) { + boxfill8(cons.sht->buf, cons.sht->bxsize, COL8_000000, + cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + } + cons.cur_c = -1; + } + if (i == 4) { /*点击命令行窗口的“×”按钮*/ + cmd_exit(&cons, fat); + } + if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/ + if (i == 8 + 256) { + /*退格键*/ + if (cons.cur_x > 16) { + /*用空格擦除光标后将光标前移一位*/ + cons_putchar(&cons, ' ', 0); + cons.cur_x -= 8; + } + } else if (i == 10 + 256) { + /*回车键*/ + /*将光标用空格擦除后换行 */ + cons_putchar(&cons, ' ', 0); + cmdline[cons.cur_x / 8 - 2] = 0; + cons_newline(&cons); + cons_runcmd(cmdline, &cons, fat, memtotal); /*运行命令*/ + if (cons.sht == 0) { + cmd_exit(&cons, fat); + } + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + } else { + /*一般字符*/ + if (cons.cur_x < 240) { + /*显示一个字符之后将光标后移一位*/ + cmdline[cons.cur_x / 8 - 2] = i - 256; + cons_putchar(&cons, i - 256, 1); + } + } + } + /*重新显示光标*/ + if (cons.sht != 0) { + if (cons.cur_c >= 0) { + boxfill8(cons.sht->buf, cons.sht->bxsize, cons.cur_c, + cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + } + sheet_refresh(cons.sht, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16); + } + } + } +} + +void cons_putchar(struct CONSOLE *cons, int chr, char move) +{ + char s[2]; + s[0] = chr; + s[1] = 0; + if (s[0] == 0x09) { /*制表符*/ + for (;;) { + if (cons->sht != 0) { + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1); + } + cons->cur_x += 8; + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + if (((cons->cur_x - 8) & 0x1f) == 0) { + break; /*被32整除则break*/ + } + } + } else if (s[0] == 0x0a) { /*换行*/ + cons_newline(cons); + } else if (s[0] == 0x0d) { /*回车*/ + /*先不做任何操作*/ + } else { /*一般字符*/ + if (cons->sht != 0) { + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1); + } + if (move != 0) { + /* move为0时光标不后移*/ + cons->cur_x += 8; + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + } + } + return; +} + +void cons_newline(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + if (cons->cur_y < 28 + 112) { + cons->cur_y += 16; /*到下一行*/ + } else { + /*滚动*/ + if (sheet != 0) { + for (y = 28; y < 28 + 112; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize]; + } + } + for (y = 28 + 112; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + } + } + cons->cur_x = 8; + return; +} + +void cons_putstr0(struct CONSOLE *cons, char *s) +{ + for (; *s != 0; s++) { + cons_putchar(cons, *s, 1); + } + return; +} + +void cons_putstr1(struct CONSOLE *cons, char *s, int l) +{ + int i; + for (i = 0; i < l; i++) { + cons_putchar(cons, s[i], 1); + } + return; +} + +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) +{ + if (strcmp(cmdline, "mem") == 0 && cons->sht != 0) { + cmd_mem(cons, memtotal); + } else if (strcmp(cmdline, "cls") == 0 && cons->sht != 0) { + cmd_cls(cons); + } else if ((strcmp(cmdline, "dir") == 0 || strcmp(cmdline, "ls") == 0) && cons->sht != 0) { + cmd_dir(cons); + } else if (strncmp(cmdline, "type ", 5) == 0 && cons->sht != 0) { + cmd_type(cons, fat, cmdline); + } else if (strcmp(cmdline, "exit") == 0) { + cmd_exit(cons, fat); + } else if (strncmp(cmdline, "start ", 6) == 0) { + cmd_start(cons, cmdline, memtotal); + } else if (strncmp(cmdline, "ncst ", 5) == 0) { + cmd_ncst(cons, cmdline, memtotal); + } else if (cmdline[0] != 0) { + if (cmd_app(cons, fat, cmdline) == 0) { + /*不是命令,不是应用程序,也不是空行*/ + cons_putstr0(cons, "Bad command.\n\n"); + } + } + return; +} + +void cmd_mem(struct CONSOLE *cons, int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + char s[60]; + sprintf(s, "total %dMB\nfree %dKB\n\n", memtotal / (1024 * 1024), memman_total(memman) / 1024); + cons_putstr0(cons, s); + return; +} + +void cmd_cls(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + for (y = 28; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + cons->cur_y = 28; + return; +} + +void cmd_dir(struct CONSOLE *cons) +{ + struct FILEINFO *finfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600); + int i, j; + char s[30]; + for (i = 0; i < 224; i++) { + if (finfo[i].name[0] == 0x00) { + break; + } + if (finfo[i].name[0] != 0xe5) { + if ((finfo[i].type & 0x18) == 0) { + sprintf(s, "filename.ext %7d\n", finfo[i].size); + for (j = 0; j < 8; j++) { + s[j] = finfo[i].name[j]; + } + s[ 9] = finfo[i].ext[0]; + s[10] = finfo[i].ext[1]; + s[11] = finfo[i].ext[2]; + cons_putstr0(cons, s); + } + } + } + cons_newline(cons); + return; +} + +void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct FILEINFO *finfo = file_search(cmdline + 5, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + char *p; + if (finfo != 0) { + /*找到文件的情况*/ + p = (char *) memman_alloc_4k(memman, finfo->size); + file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); + cons_putstr1(cons, p, finfo->size); + memman_free_4k(memman, (int) p, finfo->size); + } else { + /*没有找到文件的情况*/ + cons_putstr0(cons, "File not found.\n"); + } + cons_newline(cons); + return; +} + +void cmd_exit(struct CONSOLE *cons, int *fat) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = task_now(); + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct FIFO32 *fifo = (struct FIFO32 *) *((int *) 0x0fec); + if (cons->sht != 0) { + timer_cancel(cons->timer); + } + memman_free_4k(memman, (int) fat, 4 * 2880); + io_cli(); + if (cons->sht != 0) { + fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); /* 768〜1023 */ + } else { + fifo32_put(fifo, task - taskctl->tasks0 + 1024); /*1024~2023*/ + } + io_sti(); + for (;;) { + task_sleep(task); + } +} + +void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal) +{ + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct SHEET *sht = open_console(shtctl, memtotal); + struct FIFO32 *fifo = &sht->task->fifo; + int i; + sheet_slide(sht, 32, 4); + sheet_updown(sht, shtctl->top); + /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ + for (i = 6; cmdline[i] != 0; i++) { + fifo32_put(fifo, cmdline[i] + 256); + } + fifo32_put(fifo, 10 + 256); /*回车键*/ + cons_newline(cons); + return; +} + +void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal) +{ + struct TASK *task = open_constask(0, memtotal); + struct FIFO32 *fifo = &task->fifo; + int i; + + /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ + for (i = 5; cmdline[i] != 0; i++) { + fifo32_put(fifo, cmdline[i] + 256); + } + fifo32_put(fifo, 10 + 256); /*回车键*/ + cons_newline(cons); + return; +} + +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct FILEINFO *finfo; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + char name[18], *p, *q; + struct TASK *task = task_now(); + int i, segsiz, datsiz, esp, dathrb; + struct SHTCTL *shtctl; + struct SHEET *sht; + + /*根据命令行生成文件名*/ + for (i = 0; i < 13; i++) { + if (cmdline[i] <= ' ') { + break; + } + name[i] = cmdline[i]; + } + name[i] = 0; /*暂且将文件名的后面置为0*/ + + /*寻找文件 */ + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + if (finfo == 0 && name[i - 1] != '.') { + /*由于找不到文件,故在文件名后面加上“.hrb”后重新寻找*/ + name[i ] = '.'; + name[i + 1] = 'H'; + name[i + 2] = 'R'; + name[i + 3] = 'B'; + name[i + 4] = 0; + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + } + + if (finfo != 0) { + /*找到文件的情况*/ + p = (char *) memman_alloc_4k(memman, finfo->size); + file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); + if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) { + segsiz = *((int *) (p + 0x0000)); + esp = *((int *) (p + 0x000c)); + datsiz = *((int *) (p + 0x0010)); + dathrb = *((int *) (p + 0x0014)); + q = (char *) memman_alloc_4k(memman, segsiz); + task->ds_base = (int) q; + set_segmdesc(task->ldt + 0, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); + set_segmdesc(task->ldt + 1, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); + for (i = 0; i < datsiz; i++) { + q[esp + i] = p[dathrb + i]; + } + start_app(0x1b, 0 * 8 + 4, esp, 1 * 8 + 4, &(task->tss.esp0)); + shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + for (i = 0; i < MAX_SHEETS; i++) { + sht = &(shtctl->sheets0[i]); + if ((sht->flags & 0x11) == 0x11 && sht->task == task) { + /*找到被应用程序遗留的窗口*/ + sheet_free(sht); /*关闭*/ + } + } + timer_cancelall(&task->fifo); + memman_free_4k(memman, (int) q, segsiz); + } else { + cons_putstr0(cons, ".hrb file format error.\n"); + } + memman_free_4k(memman, (int) p, finfo->size); + cons_newline(cons); + return 1; + } + /*没有找到文件的情况*/ + return 0; +} + +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) +{ + struct TASK *task = task_now(); + int ds_base = task->ds_base; + struct CONSOLE *cons = task->cons; + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct SHEET *sht; + struct FIFO32 *sys_fifo = (struct FIFO32 *) *((int *) 0x0fec); + int *reg = &eax + 1; /* eax后面的地址*/ + /*强行改写通过PUSHAD保存的值*/ + /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */ + /* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ + int i; + + if (edx == 1) { + cons_putchar(cons, eax & 0xff, 1); + } else if (edx == 2) { + cons_putstr0(cons, (char *) ebx + ds_base); + } else if (edx == 3) { + cons_putstr1(cons, (char *) ebx + ds_base, ecx); + } else if (edx == 4) { + return &(task->tss.esp0); + } else if (edx == 5) { + sht = sheet_alloc(shtctl); + sht->task = task; + sht->flags |= 0x10; + sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax); + make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0); + sheet_slide(sht, ((shtctl->xsize - esi) / 2) & ~3, (shtctl->ysize - edi) / 2); + sheet_updown(sht, shtctl->top); /*将窗口图层高度指定为当前鼠标所在图层的高度,鼠标移到上层*/ + reg[7] = (int) sht; + } else if (edx == 6) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + putfonts8_asc(sht->buf, sht->bxsize, esi, edi, eax, (char *) ebp + ds_base); + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + ecx * 8, edi + 16); + } + } else if (edx == 7) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + boxfill8(sht->buf, sht->bxsize, ebp, eax, ecx, esi, edi); + if ((ebx & 1) == 0) { + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 8) { + memman_init((struct MEMMAN *) (ebx + ds_base)); + ecx &= 0xfffffff0; /*以16字节为单位*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 9) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + reg[7] = memman_alloc((struct MEMMAN *) (ebx + ds_base), ecx); + } else if (edx == 10) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 11) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + sht->buf[sht->bxsize * edi + esi] = eax; + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + 1, edi + 1); + } + } else if (edx == 12) { + sht = (struct SHEET *) ebx; + sheet_refresh(sht, eax, ecx, esi, edi); + } else if (edx == 13) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + hrb_api_linewin(sht, eax, ecx, esi, edi, ebp); + if ((ebx & 1) == 0) { + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 14) { + sheet_free((struct SHEET *) ebx); + } else if (edx == 15) { + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + if (eax != 0) { + task_sleep(task); /* FIFO为空,休眠并等待*/ + } else { + io_sti(); + reg[7] = -1; + return 0; + } + } + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1) { /*光标用定时器*/ + /*应用程序运行时不需要显示光标,因此总是将下次显示用的值置为1*/ + timer_init(cons->timer, &task->fifo, 1); /*下次置为1*/ + timer_settime(cons->timer, 50); + } + if (i == 2) { /*光标ON */ + cons->cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + cons->cur_c = -1; + } + if (i == 4) { /*只关闭命令行窗口*/ + timer_cancel(cons->timer); + io_cli(); + fifo32_put(sys_fifo, cons->sht - shtctl->sheets0 + 2024); /*2024~2279*/ + cons->sht = 0; + io_sti(); + } + if (i >= 256) { /*键盘数据(通过任务A)等*/ + reg[7] = i - 256; + return 0; + } + } + } else if (edx == 16) { + reg[7] = (int) timer_alloc(); + ((struct TIMER *) reg[7])->flags2 = 1; /*允许自动取消*/ + } else if (edx == 17) { + timer_init((struct TIMER *) ebx, &task->fifo, eax + 256); + } else if (edx == 18) { + timer_settime((struct TIMER *) ebx, eax); + } else if (edx == 19) { + timer_free((struct TIMER *) ebx); + } else if (edx == 20) { + if (eax == 0) { + i = io_in8(0x61); + io_out8(0x61, i & 0x0d); + } else { + i = 1193180000 / eax; + io_out8(0x43, 0xb6); + io_out8(0x42, i & 0xff); + io_out8(0x42, i >> 8); + i = io_in8(0x61); + io_out8(0x61, (i | 0x03) & 0x0f); + } + } + return 0; +} + +int *inthandler0c(int *esp) +{ + struct TASK *task = task_now(); + struct CONSOLE *cons = task->cons; + char s[30]; + cons_putstr0(cons, "\nINT 0C :\n Stack Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +int *inthandler0d(int *esp) +{ + struct TASK *task = task_now(); + struct CONSOLE *cons = task->cons; + char s[30]; + cons_putstr0(cons, "\nINT 0D :\n General Protected Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col) +{ + int i, x, y, len, dx, dy; + + dx = x1 - x0; + dy = y1 - y0; + x = x0 << 10; + y = y0 << 10; + if (dx < 0) { + dx = - dx; + } + if (dy < 0) { + dy = - dy; + } + if (dx >= dy) { + len = dx + 1; + if (x0 > x1) { + dx = -1024; + } else { + dx = 1024; + } + if (y0 <= y1) { + dy = ((y1 - y0 + 1) << 10) / len; + } else { + dy = ((y1 - y0 - 1) << 10) / len; + } + } else { + len = dy + 1; + if (y0 > y1) { + dy = -1024; + } else { + dy = 1024; + } + if (x0 <= x1) { + dx = ((x1 - x0 + 1) << 10) / len; + } else { + dx = ((x1 - x0 - 1) << 10) / len; + } + } + + for (i = 0; i < len; i++) { + sht->buf[(y >> 10) * sht->bxsize + (x >> 10)] = col; + x += dx; + y += dy; + } + + return; +} diff --git a/28_day/haribote/dsctbl.c b/28_day/haribote/dsctbl.c new file mode 100644 index 0000000..9ff2c67 --- /dev/null +++ b/28_day/haribote/dsctbl.c @@ -0,0 +1,59 @@ +/* GDT、IDT、descriptor table 关系处理 */ + +#include "bootpack.h" + +void init_gdtidt(void) +{ + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *) ADR_IDT; + int i; + + /* GDT初始化 */ + for (i = 0; i <= LIMIT_GDT / 8; i++) { + set_segmdesc(gdt + i, 0, 0, 0); + } + set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW); + set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER); + load_gdtr(LIMIT_GDT, ADR_GDT); + + /* IDT初始化 */ + for (i = 0; i <= LIMIT_IDT / 8; i++) { + set_gatedesc(idt + i, 0, 0, 0); + } + load_idtr(LIMIT_IDT, ADR_IDT); + + /* IDT设置*/ + set_gatedesc(idt + 0x0c, (int) asm_inthandler0c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x0d, (int) asm_inthandler0d, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x40, (int) asm_hrb_api, 2 * 8, AR_INTGATE32 + 0x60); + + return; +} + +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar) +{ + if (limit > 0xfffff) { + ar |= 0x8000; /* G_bit = 1 */ + limit /= 0x1000; + } + sd->limit_low = limit & 0xffff; + sd->base_low = base & 0xffff; + sd->base_mid = (base >> 16) & 0xff; + sd->access_right = ar & 0xff; + sd->limit_high = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0); + sd->base_high = (base >> 24) & 0xff; + return; +} + +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar) +{ + gd->offset_low = offset & 0xffff; + gd->selector = selector; + gd->dw_count = (ar >> 8) & 0xff; + gd->access_right = ar & 0xff; + gd->offset_high = (offset >> 16) & 0xffff; + return; +} diff --git a/28_day/haribote/fifo.c b/28_day/haribote/fifo.c new file mode 100644 index 0000000..8f28f4b --- /dev/null +++ b/28_day/haribote/fifo.c @@ -0,0 +1,63 @@ +/* FIFO */ + +#include "bootpack.h" + +#define FLAGS_OVERRUN 0x0001 + +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task) +/* FIFO缓冲区的初始化*/ +{ + fifo->size = size; + fifo->buf = buf; + fifo->free = size; /*空*/ + fifo->flags = 0; + fifo->p = 0; /*写入位置*/ + fifo->q = 0; /*读取位置*/ + fifo->task = task; /*有数据写入时需要唤醒的任务*/ + return; +} + +int fifo32_put(struct FIFO32 *fifo, int data) +/*向FIFO写入数据并累积起来*/ +{ + if (fifo->free == 0) { + /*没有空余空间,溢出*/ + fifo->flags |= FLAGS_OVERRUN; + return -1; + } + fifo->buf[fifo->p] = data; + fifo->p++; + if (fifo->p == fifo->size) { + fifo->p = 0; + } + fifo->free--; + if (fifo->task != 0) { + if (fifo->task->flags != 2) { /*如果任务处于休眠状态*/ + task_run(fifo->task, -1, 0); /*将任务唤醒*/ + } + } + return 0; +} + +int fifo32_get(struct FIFO32 *fifo) +/*从FIFO取得一个数据*/ +{ + int data; + if (fifo->free == fifo->size) { + /*当缓冲区为空的情况下返回-1*/ + return -1; + } + data = fifo->buf[fifo->q]; + fifo->q++; + if (fifo->q == fifo->size) { + fifo->q = 0; + } + fifo->free++; + return data; +} + +int fifo32_status(struct FIFO32 *fifo) +/*报告已经存储了多少数据*/ +{ + return fifo->size - fifo->free; +} diff --git a/28_day/haribote/file.c b/28_day/haribote/file.c new file mode 100644 index 0000000..bf9d063 --- /dev/null +++ b/28_day/haribote/file.c @@ -0,0 +1,74 @@ +/* 文件相关函数 */ + +#include "bootpack.h" + +void file_readfat(int *fat, unsigned char *img) +/*将磁盘映像中的FAT解压缩 */ +{ + int i, j = 0; + for (i = 0; i < 2880; i += 2) { + fat[i + 0] = (img[j + 0] | img[j + 1] << 8) & 0xfff; + fat[i + 1] = (img[j + 1] >> 4 | img[j + 2] << 4) & 0xfff; + j += 3; + } + return; +} + +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img) +{ + int i; + for (;;) { + if (size <= 512) { + for (i = 0; i < size; i++) { + buf[i] = img[clustno * 512 + i]; + } + break; + } + for (i = 0; i < 512; i++) { + buf[i] = img[clustno * 512 + i]; + } + size -= 512; + buf += 512; + clustno = fat[clustno]; + } + return; +} + +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max) +{ + int i, j; + char s[12]; + for (j = 0; j < 11; j++) { + s[j] = ' '; + } + j = 0; + for (i = 0; name[i] != 0; i++) { + if (j >= 11) { return 0; /*没有找到*/ } + if (name[i] == '.' && j <= 8) { + j = 8; + } else { + s[j] = name[i]; + if ('a' <= s[j] && s[j] <= 'z') { + /*将小写字母转换为大写字母*/ + s[j] -= 0x20; + } + j++; + } + } + for (i = 0; i < max; ) { + if (finfo->name[0] == 0x00) { + break; + } + if ((finfo[i].type & 0x18) == 0) { + for (j = 0; j < 11; j++) { + if (finfo[i].name[j] != s[j]) { + goto next; + } + } + return finfo + i; /*找到文件*/ + } +next: + i++; + } + return 0; /*没有找到*/ +} diff --git a/28_day/haribote/graphic.c b/28_day/haribote/graphic.c new file mode 100644 index 0000000..4bd6979 --- /dev/null +++ b/28_day/haribote/graphic.c @@ -0,0 +1,167 @@ +/* 关于绘图部分的处理 */ + +#include "bootpack.h" + +void init_palette(void) +{ + static unsigned char table_rgb[16 * 3] = { + 0x00, 0x00, 0x00, /* 0:黑 */ + 0xff, 0x00, 0x00, /* 1:梁红 */ + 0x00, 0xff, 0x00, /* 2:亮绿 */ + 0xff, 0xff, 0x00, /* 3:亮黄 */ + 0x00, 0x00, 0xff, /* 4:亮蓝 */ + 0xff, 0x00, 0xff, /* 5:亮紫 */ + 0x00, 0xff, 0xff, /* 6:浅亮蓝 */ + 0xff, 0xff, 0xff, /* 7:白 */ + 0xc6, 0xc6, 0xc6, /* 8:亮灰 */ + 0x84, 0x00, 0x00, /* 9:暗红 */ + 0x00, 0x84, 0x00, /* 10:暗绿 */ + 0x84, 0x84, 0x00, /* 11:暗黄 */ + 0x00, 0x00, 0x84, /* 12:暗青 */ + 0x84, 0x00, 0x84, /* 13:暗紫 */ + 0x00, 0x84, 0x84, /* 14:浅暗蓝 */ + 0x84, 0x84, 0x84 /* 15:暗灰 */ + }; + unsigned char table2[216 * 3]; + int r, g, b; + set_palette(0, 15, table_rgb); + for (b = 0; b < 6; b++) { + for (g = 0; g < 6; g++) { + for (r = 0; r < 6; r++) { + table2[(r + g * 6 + b * 36) * 3 + 0] = r * 51; + table2[(r + g * 6 + b * 36) * 3 + 1] = g * 51; + table2[(r + g * 6 + b * 36) * 3 + 2] = b * 51; + } + } + } + set_palette(16, 231, table2); + return; +} + +void set_palette(int start, int end, unsigned char *rgb) +{ + int i, eflags; + eflags = io_load_eflags(); /* 记录中断许可标志的值 */ + io_cli(); /* 将中断许可标志置为0,禁止中断 */ + io_out8(0x03c8, start); + for (i = start; i <= end; i++) { + io_out8(0x03c9, rgb[0] / 4); + io_out8(0x03c9, rgb[1] / 4); + io_out8(0x03c9, rgb[2] / 4); + rgb += 3; + } + io_store_eflags(eflags); /* 复原中断许可标志 */ + return; +} + +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) +{ + int x, y; + for (y = y0; y <= y1; y++) { + for (x = x0; x <= x1; x++) + vram[y * xsize + x] = c; + } + return; +} + +void init_screen8(char *vram, int x, int y) +{ + boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28); + boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1); + + boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24); + boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4); + boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4); + boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5); + boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3); + boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3); + + boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24); + boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4); + boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3); + boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3); + return; +} + +void putfont8(char *vram, int xsize, int x, int y, char c, char *font) +{ + int i; + char *p, d /* data */; + for (i = 0; i < 16; i++) { + p = vram + (y + i) * xsize + x; + d = font[i]; + if ((d & 0x80) != 0) { p[0] = c; } + if ((d & 0x40) != 0) { p[1] = c; } + if ((d & 0x20) != 0) { p[2] = c; } + if ((d & 0x10) != 0) { p[3] = c; } + if ((d & 0x08) != 0) { p[4] = c; } + if ((d & 0x04) != 0) { p[5] = c; } + if ((d & 0x02) != 0) { p[6] = c; } + if ((d & 0x01) != 0) { p[7] = c; } + } + return; +} + +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s) +{ + extern char hankaku[4096]; + /* C语言中,字符串都是以0x00结尾 */ + for (; *s != 0x00; s++) { + putfont8(vram, xsize, x, y, c, hankaku + *s * 16); + x += 8; + } + return; +} + +void init_mouse_cursor8(char *mouse, char bc) +/* 鼠标的数据准备(16x16) */ +{ + static char cursor[16][16] = { + "**************..", + "*OOOOOOOOOOO*...", + "*OOOOOOOOOO*....", + "*OOOOOOOOO*.....", + "*OOOOOOOO*......", + "*OOOOOOO*.......", + "*OOOOOOO*.......", + "*OOOOOOOO*......", + "*OOOO**OOO*.....", + "*OOO*..*OOO*....", + "*OO*....*OOO*...", + "*O*......*OOO*..", + "**........*OOO*.", + "*..........*OOO*", + "............*OO*", + ".............***" + }; + int x, y; + + for (y = 0; y < 16; y++) { + for (x = 0; x < 16; x++) { + if (cursor[y][x] == '*') { + mouse[y * 16 + x] = COL8_000000; + } + if (cursor[y][x] == 'O') { + mouse[y * 16 + x] = COL8_FFFFFF; + } + if (cursor[y][x] == '.') { + mouse[y * 16 + x] = bc; + } + } + } + return; +} + +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize) +{ + int x, y; + for (y = 0; y < pysize; y++) { + for (x = 0; x < pxsize; x++) { + vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x]; + } + } + return; +} diff --git a/28_day/haribote/hankaku.txt b/28_day/haribote/hankaku.txt new file mode 100644 index 0000000..62d56f9 --- /dev/null +++ b/28_day/haribote/hankaku.txt @@ -0,0 +1,4609 @@ +OSASK̔ptHg𗬗p + +char 0x00 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x01 +........ +........ +..***... +.*...*.. +*.....*. +*.*.*.*. +*.*.*.*. +*.....*. +*.....*. +*.*.*.*. +*..*..*. +.*...*.. +..***... +........ +........ +........ + +char 0x02 +........ +........ +..***... +.*****.. +*******. +**.*.**. +**.*.**. +*******. +*******. +**.*.**. +***.***. +.*****.. +..***... +........ +........ +........ + +char 0x03 +........ +........ +........ +........ +.**.**.. +*******. +*******. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x04 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x05 +........ +........ +........ +........ +...*.... +..***... +.*.*.*.. +*******. +.*.*.*.. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x06 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +**.*.**. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x07 +........ +........ +........ +........ +........ +........ +...**... +..****.. +..****.. +...**... +........ +........ +........ +........ +........ +........ + +char 0x08 +******** +******** +******** +******** +******** +******** +***..*** +**....** +**....** +***..*** +******** +******** +******** +******** +******** +******** + +char 0x09 +........ +........ +........ +........ +........ +..****.. +.**..**. +.*....*. +.*....*. +.**..**. +..****.. +........ +........ +........ +........ +........ + +char 0x0a +******** +******** +******** +******** +******** +**....** +*..**..* +*.****.* +*.****.* +*..**..* +**....** +******** +******** +******** +******** +******** + +char 0x0b +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x0c +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ + +char 0x0d +........ +........ +....**.. +....***. +....*.** +....*.** +....*.*. +....*... +....*... +...**... +.****... +*****... +.***.... +........ +........ +........ + +char 0x0e +........ +........ +...***** +...***** +...*...* +...*...* +...*...* +...*...* +...*...* +...*...* +.***.*** +******** +.**..**. +........ +........ +........ + +char 0x0f +........ +........ +........ +........ +...*.... +.*.*.*.. +..***... +..*.*... +..***... +.*.*.*.. +...*.... +........ +........ +........ +........ +........ + +char 0x10 +........ +*....... +**...... +***..... +****.... +*****... +******.. +*******. +******.. +*****... +****.... +***..... +**...... +*....... +........ +........ + +char 0x11 +........ +......*. +.....**. +....***. +...****. +..*****. +.******. +*******. +.******. +..*****. +...****. +....***. +.....**. +......*. +........ +........ + +char 0x12 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ +........ + +char 0x13 +........ +........ +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +........ +........ +.*...*.. +.*...*.. +........ +........ + +char 0x14 +........ +..*****. +.*..*.*. +*...*.*. +*...*.*. +*...*.*. +*...*.*. +.*..*.*. +..***.*. +....*.*. +....*.*. +....*.*. +....*.*. +....*.*. +........ +........ + +char 0x15 +.*****.. +*.....*. +.*...... +..*..... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +....*... +.....*.. +*.....*. +.*****.. +........ + +char 0x16 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*******. +*******. +........ +........ + +char 0x17 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +.*****.. +........ +........ + +char 0x18 +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x19 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ + +char 0x1a +........ +........ +........ +........ +...*.... +....*... +.....*.. +*******. +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ + +char 0x1b +........ +........ +........ +........ +...*.... +..*..... +.*...... +*******. +.*...... +..*..... +...*.... +........ +........ +........ +........ +........ + +char 0x1c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*....... +*....... +*******. +........ +........ + +char 0x1d +........ +........ +........ +........ +........ +..*.*... +.*...*.. +*******. +.*...*.. +..*.*... +........ +........ +........ +........ +........ +........ + +char 0x1e +........ +........ +........ +........ +...*.... +...*.... +..***... +..***... +.*****.. +.*****.. +*******. +*******. +........ +........ +........ +........ + +char 0x1f +........ +........ +........ +........ +*******. +*******. +.*****.. +.*****.. +..***... +..***... +...*.... +...*.... +........ +........ +........ +........ + +char 0x20 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x21 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ +...*.... +...*.... +........ +........ + +char 0x22 +..*.*... +..*.*... +..*.*... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x23 +........ +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +........ +........ + +char 0x24 +...*.... +..***.*. +.*.*.**. +*..*..*. +*..*..*. +*..*.... +.*.*.... +..***... +...*.*.. +...*..*. +*..*..*. +*..*..*. +**.*.*.. +*.***... +...*.... +...*.... + +char 0x25 +.**...*. +*..*..*. +*..*.*.. +*..*.*.. +.**.*... +....*... +...*.... +...*.... +..*..... +..*.**.. +.*.*..*. +.*.*..*. +*..*..*. +*...**.. +........ +........ + +char 0x26 +........ +.***.... +*...*... +*...*... +*...*... +*..*.... +.**..... +.*...*** +*.*...*. +*..*..*. +*...*.*. +*....*.. +.*...**. +..***..* +........ +........ + +char 0x27 +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x28 +......*. +.....*.. +....*... +....*... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....*... +....*... +.....*.. +......*. +........ + +char 0x29 +*....... +.*...... +..*..... +..*..... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..*..... +..*..... +.*...... +*....... +........ + +char 0x2a +........ +........ +........ +........ +........ +...*.... +*..*..*. +.*.*.*.. +..***... +.*.*.*.. +*..*..*. +...*.... +........ +........ +........ +........ + +char 0x2b +........ +........ +........ +........ +........ +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ +........ +........ + +char 0x2c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x2d +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ +........ +........ +........ +........ +........ +........ + +char 0x2e +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x2f +......*. +......*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*...... +.*...... +*....... +*....... + +char 0x30 +........ +...**... +..*..*.. +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +...**... +........ +........ + +char 0x31 +........ +....*... +...**... +..*.*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +..*****. +........ +........ + +char 0x32 +........ +...**... +..*..*.. +.*....*. +.*....*. +......*. +.....*.. +....*... +...*.... +..*..... +..*..... +.*...... +.*...... +.******. +........ +........ + +char 0x33 +........ +...**... +..*..*.. +.*....*. +......*. +......*. +.....*.. +...**... +.....*.. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x34 +........ +....**.. +....**.. +....**.. +...*.*.. +...*.*.. +...*.*.. +..*..*.. +..*..*.. +.*...*.. +.******. +.....*.. +.....*.. +...****. +........ +........ + +char 0x35 +........ +.*****.. +.*...... +.*...... +.*...... +.*.**... +.**..*.. +......*. +......*. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x36 +........ +...**... +..*..*.. +.*....*. +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x37 +........ +.******. +.*....*. +.*....*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x38 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x39 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..**. +...**.*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x3a +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x3b +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x3c +........ +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +........ + +char 0x3d +........ +........ +........ +........ +........ +........ +*******. +........ +........ +*******. +........ +........ +........ +........ +........ +........ + +char 0x3e +........ +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +........ + +char 0x3f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.....*.. +....*... +...*.... +...*.... +........ +........ +...**... +...**... +........ +........ + +char 0x40 +........ +..***... +.*...*.. +*.....*. +*..**.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*..***.. +*....... +.*...**. +..***... +........ +........ + +char 0x41 +........ +...**... +...**... +...**... +...**... +..*..*.. +..*..*.. +..*..*.. +..*..*.. +.******. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x42 +........ +****.... +.*..*... +.*...*.. +.*...*.. +.*...*.. +.*..*... +.****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +*****... +........ +........ + +char 0x43 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*....... +*....... +*....... +*.....*. +.*....*. +.*...*.. +..***... +........ +........ + +char 0x44 +........ +*****... +.*...*.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...*.. +.*...*.. +*****... +........ +........ + +char 0x45 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x46 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...*.. +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x47 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*..****. +*.....*. +*.....*. +*.....*. +.*....*. +.*...**. +..***... +........ +........ + +char 0x48 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.******. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x49 +........ +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x4a +........ +...***** +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +*....*.. +.*..*... +..**.... +........ + +char 0x4b +........ +***..*** +.*....*. +.*...*.. +.*..*... +.*.*.... +.*.*.... +.**..... +.*.*.... +.*.*.... +.*..*... +.*...*.. +.*....*. +***..*** +........ +........ + +char 0x4c +........ +****.... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x4d +........ +**....** +.*....*. +.**..**. +.**..**. +.**..**. +.*.**.*. +.*.**.*. +.*.**.*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x4e +........ +**...*** +.*....*. +.**...*. +.**...*. +.*.*..*. +.*.*..*. +.*.*..*. +.*..*.*. +.*..*.*. +.*..*.*. +.*...**. +.*...**. +***...*. +........ +........ + +char 0x4f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x50 +........ +*****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +.****... +.*...... +.*...... +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x51 +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*..*..*. +*...*.*. +.*...*.. +..***.*. +........ +........ + +char 0x52 +........ +******.. +.*....*. +.*....*. +.*....*. +.*....*. +.*****.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x53 +........ +..***.*. +.*...**. +*.....*. +*.....*. +*....... +.*...... +..***... +.....*.. +......*. +*.....*. +*.....*. +**...*.. +*.***... +........ +........ + +char 0x54 +........ +*******. +*..*..*. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x55 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..****.. +........ +........ + +char 0x56 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...**... +...**... +........ +........ + +char 0x57 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x58 +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +..*..*.. +..*..*.. +..*..*.. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x59 +........ +***.***. +.*...*.. +.*...*.. +.*...*.. +..*.*... +..*.*... +..*.*... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x5a +........ +*******. +*....*.. +*....*.. +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*....*. +*.....*. +*******. +........ +........ + +char 0x5b +........ +..*****. +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*****. +........ + +char 0x5c +*....... +*....... +.*...... +.*...... +..*..... +..*..... +..*..... +...*.... +...*.... +....*... +....*... +.....*.. +.....*.. +.....*.. +......*. +......*. + +char 0x5d +........ +.*****.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.*****.. +........ + +char 0x5e +........ +...*.... +..*.*... +.*...*.. +*.....*. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x5f +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ + +char 0x60 +...*.... +....*... +.....*.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x61 +........ +........ +........ +........ +........ +.***.... +....*... +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +*...**.. +.***.**. +........ +........ + +char 0x62 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +........ +........ + +char 0x63 +........ +........ +........ +........ +........ +..**.... +.*..**.. +*....*.. +*....*.. +*....... +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x64 +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.**. +........ +........ + +char 0x65 +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +******.. +*....... +*.....*. +.*....*. +..****.. +........ +........ + +char 0x66 +....***. +...*.... +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x67 +........ +........ +........ +........ +........ +..**.**. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +.....*.. +.****... + +char 0x68 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x69 +........ +...*.... +...*.... +........ +........ +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6a +........ +.....*.. +.....*.. +........ +........ +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +....*... +....*... +..**.... + +char 0x6b +**...... +.*...... +.*...... +.*...... +.*...... +.*..***. +.*...*.. +.*..*... +.*.*.... +.**..... +.*.*.... +.*..*... +.*...*.. +***..**. +........ +........ + +char 0x6c +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6d +........ +........ +........ +........ +........ +****.**. +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +**.**.** +........ +........ + +char 0x6e +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x6f +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x70 +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +.*...... +***..... + +char 0x71 +........ +........ +........ +........ +........ +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +....***. + +char 0x72 +........ +........ +........ +........ +........ +**.***.. +.**...*. +.*....*. +.*...... +.*...... +.*...... +.*...... +.*...... +***..... +........ +........ + +char 0x73 +........ +........ +........ +........ +........ +.****.*. +*....**. +*.....*. +**...... +..***... +.....**. +*.....*. +**....*. +*.****.. +........ +........ + +char 0x74 +........ +........ +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....***. +........ +........ + +char 0x75 +........ +........ +........ +........ +........ +**...**. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...**. +..***.** +........ +........ + +char 0x76 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +........ +........ + +char 0x77 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x78 +........ +........ +........ +........ +........ +**...**. +.*...*.. +..*.*... +..*.*... +...*.... +..*.*... +..*.*... +.*...*.. +**...**. +........ +........ + +char 0x79 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...*.... +...*.... +.**..... + +char 0x7a +........ +........ +........ +........ +........ +*******. +*.....*. +*....*.. +....*... +...*.... +..*..... +.*....*. +*.....*. +*******. +........ +........ + +char 0x7b +........ +.....**. +....*... +...*.... +...*.... +...*.... +...*.... +.**..... +...*.... +...*.... +...*.... +...*.... +....*... +.....**. +........ +........ + +char 0x7c +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0x7d +........ +.**..... +...*.... +....*... +....*... +....*... +....*... +.....**. +....*... +....*... +....*... +....*... +...*.... +.**..... +........ +........ + +char 0x7e +........ +.***..*. +*...**.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x7f +........ +........ +........ +........ +...*.... +..*.*... +.*...*.. +*.....*. +*******. +*.....*. +*******. +........ +........ +........ +........ +........ + +char 0x80 +........ +..***... +.*...*.. +*.....*. +*....... +*....... +*....... +*....... +*....... +*....... +*....... +*.....*. +.*...*.. +..***... +...*.... +..*..... + +char 0x81 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x82 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x83 +........ +...*.... +..*.*... +.*...*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x84 +........ +........ +..*..*.. +..*..*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x85 +...*.... +....*... +.....*.. +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x86 +........ +...**... +..*..*.. +...**... +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x87 +........ +........ +........ +........ +........ +..****.. +.*....*. +*....... +*....... +*....... +*....... +*....... +.*....*. +..****.. +....*... +...*.... + +char 0x88 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x89 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8a +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8b +........ +........ +..*..*.. +..*..*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8c +........ +...*.... +..*.*... +.*...*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8d +...*.... +....*... +.....*.. +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8e +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x8f +........ +..***... +.*...*.. +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x90 +....**.. +....*... +...*.... +*******. +*....... +*....... +*....... +*....... +*****... +*....... +*....... +*....... +*....... +*******. +........ +........ + +char 0x91 +........ +........ +........ +........ +........ +.**..... +...***.. +...*..*. +.***..*. +*..****. +*..*.... +*..*.... +*..*..*. +.**.**.. +........ +........ + +char 0x92 +....**.. +...*.... +..*..... +..*.*... +..*.*... +..*.*... +*******. +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +........ +........ + +char 0x93 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x94 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x95 +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x96 +........ +...*.... +..*.*... +.*...*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x97 +...*.... +....*... +.....*.. +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x98 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +.*...*.. +.*...*.. +..*.*... +..*.*... +...*.... +...*.... +..*..... +..*..... +.*...... + +char 0x99 +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9a +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9b +........ +..*.*... +..*.*... +..*.*... +..****.. +.**.*.*. +*.*.*... +*.*.*... +*.*.*... +*.*.*... +*.*.*... +.**.*.*. +..****.. +..*.*... +..*.*... +..*.*... + +char 0x9c +........ +....**.. +...*..*. +..*..... +..*..... +..*..... +******.. +..*..... +..*..... +..*..... +.**..... +*.*..... +*.**..*. +.*..**.. +........ +........ + +char 0x9d +........ +*.....*. +*.....*. +.*...*.. +..*.*... +...*.... +*******. +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x9e +........ +***..... +*..*.... +*...*... +*...*... +*...*... +*..*.*.. +***..*.. +*..***** +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +........ +........ + +char 0x9f +........ +....**.. +...*..*. +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +...*.... +*..*.... +.**..... +........ +........ + +char 0xa0 +....**.. +....*... +...*.... +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0xa1 +....**.. +....*... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xa2 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa3 +....**.. +....*... +...*.... +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0xa4 +........ +...*..*. +..*.*.*. +..*..*.. +........ +*****... +*....*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0xa5 +...*..*. +..*.*.*. +..*..*.. +........ +*.....*. +**....*. +**....*. +*.*...*. +*..*..*. +*..*..*. +*...*.*. +*....**. +*....**. +*.....*. +........ +........ + +char 0xa6 +........ +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +*******. +........ +........ + +char 0xa7 +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +*******. +........ +........ + +char 0xa8 +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +..*..... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*....... +*....... +*....... +........ +........ + +char 0xaa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +......*. +......*. +......*. +........ +........ + +char 0xab +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +.****... +.....*.. +..***... +.*...... +.*****.. +........ +........ + +char 0xac +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +...**... +..*.*... +.*..*... +.*****.. +....*... +........ +........ + +char 0xad +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xae +........ +........ +........ +........ +...*..*. +..*..*.. +.*..*... +*..*.... +*..*.... +.*..*... +..*..*.. +...*..*. +........ +........ +........ +........ + +char 0xaf +........ +........ +........ +........ +*..*.... +.*..*... +..*..*.. +...*..*. +...*..*. +..*..*.. +.*..*... +*..*.... +........ +........ +........ +........ + +char 0xb0 +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. + +char 0xb1 +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. + +char 0xb2 +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* + +char 0xb3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb6 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb7 +........ +........ +........ +........ +........ +........ +........ +******.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb8 +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb9 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xba +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbb +........ +........ +........ +........ +........ +........ +........ +******.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +******.. +........ +........ +........ +........ +........ +........ + +char 0xbd +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******.. +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xbe +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +........ +........ +........ +........ +........ +........ + +char 0xbf +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc0 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc1 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc4 +........ +........ +........ +........ +........ +........ +........ +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc6 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xc8 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xc9 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xca +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xcb +........ +........ +........ +........ +........ +........ +........ +******** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcd +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xce +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcf +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xd0 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd1 +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd3 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xd5 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd6 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd8 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd9 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xda +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xdb +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdc +........ +........ +........ +........ +........ +........ +........ +........ +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdd +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... + +char 0xde +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** + +char 0xdf +******** +******** +******** +******** +******** +******** +******** +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xea +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xeb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xec +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xed +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xee +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xef +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfc +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfd +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfe +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xff +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ diff --git a/28_day/haribote/haribote.sys b/28_day/haribote/haribote.sys new file mode 100644 index 0000000000000000000000000000000000000000..e098d2b2dc72ce95ff296ef38e8f320f59a0abbd GIT binary patch literal 33331 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 + +void init_pic(void) +/* PIC初始化 */ +{ + io_out8(PIC0_IMR, 0xff ); /* 禁止所有中断 */ + io_out8(PIC1_IMR, 0xff ); /* 禁止所有中断 */ + + io_out8(PIC0_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC0_ICW2, 0x20 ); /* IRQ0-7由INT20-27接收 */ + io_out8(PIC0_ICW3, 1 << 2); /* PIC1由IRQ2相连 */ + io_out8(PIC0_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC1_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC1_ICW2, 0x28 ); /* IRQ8-15由INT28-2f接收 */ + io_out8(PIC1_ICW3, 2 ); /* PIC1由IRQ2连接 */ + io_out8(PIC1_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外全部禁止 */ + io_out8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中断 */ + + return; +} diff --git a/28_day/haribote/ipl10.bin b/28_day/haribote/ipl10.bin new file mode 100644 index 0000000000000000000000000000000000000000..9ac675e6579d9ff288934f5c4a7cbf633f1e7076 GIT binary patch literal 512 zcmaFuH^IX($kWL`#Fc@Gk&%Jv0fPhg2Tled1||j&aNq`!n*V_Srp`ZD!Obzm&`3c+ z0VIbCb}%sXUD(4=(|2Qs0!QD0tqj{3HZtvFVA#U6fpIqj!zPBa!o>p3#~7Rcu@)O` z0rOu!?m57!z|eP~;UHtfPoc7l8yOppF*f{TDmuQ6q2VZF!(XnVy&ZZV_+JLPf{Z_~ y?@Ub>3(yQ3h7!&#e7pG>&I-JK_vQ6pF0P#X#1w_pqN4mFE>vfY^00= 5 跳转到error + MOV AH,0x00 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 重置驱动器 + JMP retry +next: + MOV AX,ES ; 把内存地址后移0x200(512/16十六进制转换) + ADD AX,0x0020 + MOV ES,AX ; ADD ES,0x020因为没有ADD ES,只能通过AX进行 + ADD CL,1 ; 往CL里面加1 + CMP CL,18 ; 比较CL与18 + JBE readloop ; CL <= 18 跳转到readloop + MOV CL,1 + ADD DH,1 + CMP DH,2 + JB readloop ; DH < 2 跳转到readloop + MOV DH,0 + ADD CH,1 + CMP CH,CYLS + JB readloop ; CH < CYLS 跳转到readloop + +; 读取完毕,跳转到haribote.sys执行! + MOV [0x0ff0],CH ; IPLがどこまで読んだのかをメモ + JMP 0xc200 + +error: + MOV SI,msg + +putloop: + MOV AL,[SI] + ADD SI,1 ; 给SI加1 + CMP AL,0 + JE fin + MOV AH,0x0e ; 显示一个文字 + MOV BX,15 ; 指定字符颜色 + INT 0x10 ; 调用显卡BIOS + JMP putloop + +fin: + HLT ; 让CPU停止,等待指令 + JMP fin ; 无限循环 + +msg: + DB 0x0a, 0x0a ; 换行两次 + DB "load error" + DB 0x0a ; 换行 + DB 0 + + RESB 0x7dfe-$ ; 填写0x00直到0x001fe + + DB 0x55, 0xaa diff --git a/28_day/haribote/keyboard.c b/28_day/haribote/keyboard.c new file mode 100644 index 0000000..eb5140a --- /dev/null +++ b/28_day/haribote/keyboard.c @@ -0,0 +1,44 @@ +/* 键盘控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *keyfifo; +int keydata0; + +void inthandler21(int *esp) +{ + int data; + io_out8(PIC0_OCW2, 0x61); /* 把IRQ-01接收信号结束的信息通知给PIC */ + data = io_in8(PORT_KEYDAT); + fifo32_put(keyfifo, data + keydata0); + return; +} + +#define PORT_KEYSTA 0x0064 +#define KEYSTA_SEND_NOTREADY 0x02 +#define KEYCMD_WRITE_MODE 0x60 +#define KBC_MODE 0x47 + +void wait_KBC_sendready(void) +{ + /* 等待键盘控制电路准备完毕 */ + for (;;) { + if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) { + break; + } + } + return; +} + +void init_keyboard(struct FIFO32 *fifo, int data0) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + keyfifo = fifo; + keydata0 = data0; + /* 键盘控制器的初始化 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, KBC_MODE); + return; +} diff --git a/28_day/haribote/make.bat b/28_day/haribote/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/haribote/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/haribote/memory.c b/28_day/haribote/memory.c new file mode 100644 index 0000000..54a447a --- /dev/null +++ b/28_day/haribote/memory.c @@ -0,0 +1,162 @@ +/* �������֌W */ + +#include "bootpack.h" + +#define EFLAGS_AC_BIT 0x00040000 +#define CR0_CACHE_DISABLE 0x60000000 + +unsigned int memtest(unsigned int start, unsigned int end) +{ + char flg486 = 0; + unsigned int eflg, cr0, i; + + /* 确认CPU是386还是486以上的 */ + eflg = io_load_eflags(); + eflg |= EFLAGS_AC_BIT; /* AC-bit = 1 */ + io_store_eflags(eflg); + eflg = io_load_eflags(); + if ((eflg & EFLAGS_AC_BIT) != 0) { + /* 如果是386,即使设定AC=1,AC的值还会自动回到0 */ + flg486 = 1; + } + + eflg &= ~EFLAGS_AC_BIT; /* AC-bit = 0 */ + io_store_eflags(eflg); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 |= CR0_CACHE_DISABLE; /* 禁止缓存 */ + store_cr0(cr0); + } + + i = memtest_sub(start, end); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 &= ~CR0_CACHE_DISABLE; /* 允许缓存 */ + store_cr0(cr0); + } + + return i; +} + +void memman_init(struct MEMMAN *man) +{ + man->frees = 0; /* 可用信息数目 */ + man->maxfrees = 0; /* 用于观察可用状况:frees的最大值 */ + man->lostsize = 0; /* 释放失败的内存的大小总和 */ + man->losts = 0; /* 释放失败次数 */ + return; +} + +unsigned int memman_total(struct MEMMAN *man) +/* 报告空余内存大小的合计 */ +{ + unsigned int i, t = 0; + for (i = 0; i < man->frees; i++) { + t += man->free[i].size; + } + return t; +} + +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size) +/* 分配 */ +{ + unsigned int i, a; + for (i = 0; i < man->frees; i++) { + if (man->free[i].size >= size) { + /* 找到了足够大的内存 */ + a = man->free[i].addr; + man->free[i].addr += size; + man->free[i].size -= size; + if (man->free[i].size == 0) { + /* 如果free[i]变成了0,就减掉一条可用信息 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 代入结构体 */ + } + } + return a; + } + } + return 0; /* 没有可用空间 */ +} + +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size) +/* 释放 */ +{ + int i, j; + /* 为便于归纳内存,将free[]按照addr的顺序排列 */ + /* 所以,先决定应该放在哪里 */ + for (i = 0; i < man->frees; i++) { + if (man->free[i].addr > addr) { + break; + } + } + /* free[i - 1].addr < addr < free[i].addr */ + if (i > 0) { + /* 前面有可用内存 */ + if (man->free[i - 1].addr + man->free[i - 1].size == addr) { + /* 可以与前面的可用内存归纳到一起 */ + man->free[i - 1].size += size; + if (i < man->frees) { + /* 后面也有 */ + if (addr + size == man->free[i].addr) { + /* 也可以与后面的可用内存归纳到一起 */ + man->free[i - 1].size += man->free[i].size; + /* man->free[i]删除 */ + /* free[i]变成0后归纳到前面去 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 结构体赋值 */ + } + } + } + return 0; /* 成功完成 */ + } + } + /* 不能与前面的可用空间归纳到一起 */ + if (i < man->frees) { + /* 后面还有 */ + if (addr + size == man->free[i].addr) { + /* 可以与后面的内容归纳到一起 */ + man->free[i].addr = addr; + man->free[i].size += size; + return 0; /* 成功完成 */ + } + } + /* 既不能与前面归纳到一起,也不能与后面归纳到一起 */ + if (man->frees < MEMMAN_FREES) { + /* free[i]之后的,向后移动,腾出一点可用空间 */ + for (j = man->frees; j > i; j--) { + man->free[j] = man->free[j - 1]; + } + man->frees++; + if (man->maxfrees < man->frees) { + man->maxfrees = man->frees; /* 更新最大值 */ + } + man->free[i].addr = addr; + man->free[i].size = size; + return 0; /* 成功完成 */ + } + /* 不能往后移动 */ + man->losts++; + man->lostsize += size; + return -1; /* 失败 */ +} + +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size) +{ + unsigned int a; + size = (size + 0xfff) & 0xfffff000; + a = memman_alloc(man, size); + return a; +} + +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size) +{ + int i; + size = (size + 0xfff) & 0xfffff000; + i = memman_free(man, addr, size); + return i; +} diff --git a/28_day/haribote/mouse.c b/28_day/haribote/mouse.c new file mode 100644 index 0000000..0c6403e --- /dev/null +++ b/28_day/haribote/mouse.c @@ -0,0 +1,76 @@ +/* 鼠标控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *mousefifo; +int mousedata0; + +void inthandler2c(int *esp) +/* 来自PS/2鼠标的中断 */ +{ + int data; + io_out8(PIC1_OCW2, 0x64); /* 把IRQ-12接收信号结束的信息通知给PIC1 */ + io_out8(PIC0_OCW2, 0x62); /* 把IRQ-02接收信号结束的信息通知给PIC0 */ + data = io_in8(PORT_KEYDAT); + fifo32_put(mousefifo, data + mousedata0); + return; +} + +#define KEYCMD_SENDTO_MOUSE 0xd4 +#define MOUSECMD_ENABLE 0xf4 + +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + mousefifo = fifo; + mousedata0 = data0; + /* 鼠标有效 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, MOUSECMD_ENABLE); + /* 顺利的话,ACK(0xfa)会被发送*/ + mdec->phase = 0; /* 等待鼠标的0xfa的阶段*/ +return; +} + +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat) +{ + if (mdec->phase == 0) { + /* 等待鼠标的0xfa的阶段 */ + if (dat == 0xfa) { + mdec->phase = 1; + } + return 0; + } + if (mdec->phase == 1) { + /* 等待鼠标第一字节的阶段 */ + mdec->buf[0] = dat; + mdec->phase = 2; + return 0; + } + if (mdec->phase == 2) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[1] = dat; + mdec->phase = 3; + return 0; + } + if (mdec->phase == 3) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[2] = dat; + mdec->phase = 1; + mdec->btn = mdec->buf[0] & 0x07; + mdec->x = mdec->buf[1]; + mdec->y = mdec->buf[2]; + if ((mdec->buf[0] & 0x10) != 0) { + mdec->x |= 0xffffff00; + } + if ((mdec->buf[0] & 0x20) != 0) { + mdec->y |= 0xffffff00; + } + mdec->y = - mdec->y; /* 鼠标的y方向与画面符号相反 */ + return 1; + } + /* 应该不可能到这里来 */ + return -1; +} diff --git a/28_day/haribote/mtask.c b/28_day/haribote/mtask.c new file mode 100644 index 0000000..f67b935 --- /dev/null +++ b/28_day/haribote/mtask.c @@ -0,0 +1,203 @@ +/* 多任务管理 */ + +#include "bootpack.h" + +struct TASKCTL *taskctl; +struct TIMER *task_timer; + +struct TASK *task_now(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + return tl->tasks[tl->now]; +} + +void task_add(struct TASK *task) +{ + struct TASKLEVEL *tl = &taskctl->level[task->level]; + tl->tasks[tl->running] = task; + tl->running++; + task->flags = 2; /*活动中*/ + return; +} + +void task_remove(struct TASK *task) +{ + int i; + struct TASKLEVEL *tl = &taskctl->level[task->level]; + + /*寻找task所在的位置*/ + for (i = 0; i < tl->running; i++) { + if (tl->tasks[i] == task) { + /*在这里 */ + break; + } + } + + tl->running--; + if (i < tl->now) { + tl->now--; /*需要移动成员,要相应地处理 */ + } + if (tl->now >= tl->running) { + /*如果now的值出现异常,则进行修正*/ + tl->now = 0; + } + task->flags = 1; /* 休眠中 */ + + /* 移动 */ + for (; i < tl->running; i++) { + tl->tasks[i] = tl->tasks[i + 1]; + } + return; +} + +void task_switchsub(void) +{ + int i; + /*寻找最上层的LEVEL */ + for (i = 0; i < MAX_TASKLEVELS; i++) { + if (taskctl->level[i].running > 0) { + break; /*找到了*/ + } + } + taskctl->now_lv = i; + taskctl->lv_change = 0; + return; +} + +void task_idle(void) +{ + for (;;) { + io_hlt(); + } +} + +struct TASK *task_init(struct MEMMAN *memman) +{ + int i; + struct TASK *task, *idle; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + + + taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL)); + for (i = 0; i < MAX_TASKS; i++) { + taskctl->tasks0[i].flags = 0; + taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8; + taskctl->tasks0[i].tss.ldtr = (TASK_GDT0 + MAX_TASKS + i) * 8; + set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32); + set_segmdesc(gdt + TASK_GDT0 + MAX_TASKS + i, 15, (int) taskctl->tasks0[i].ldt, AR_LDT); + } + for (i = 0; i < MAX_TASKLEVELS; i++) { + taskctl->level[i].running = 0; + taskctl->level[i].now = 0; + } + + task = task_alloc(); + task->flags = 2; /*活动中标志*/ + task->priority = 2; /* 0.02秒*/ + task->level = 0; /*最高LEVEL */ + task_add(task); + task_switchsub(); /* LEVEL 设置*/ + load_tr(task->sel); + task_timer = timer_alloc(); + timer_settime(task_timer, task->priority); + + idle = task_alloc(); + idle->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024; + idle->tss.eip = (int) &task_idle; + idle->tss.es = 1 * 8; + idle->tss.cs = 2 * 8; + idle->tss.ss = 1 * 8; + idle->tss.ds = 1 * 8; + idle->tss.fs = 1 * 8; + idle->tss.gs = 1 * 8; + task_run(idle, MAX_TASKLEVELS - 1, 1); + + return task; +} + +struct TASK *task_alloc(void) +{ + int i; + struct TASK *task; + for (i = 0; i < MAX_TASKS; i++) { + if (taskctl->tasks0[i].flags == 0) { + task = &taskctl->tasks0[i]; + task->flags = 1; /*正在使用的标志*/ + task->tss.eflags = 0x00000202; /* IF = 1; */ + task->tss.eax = 0; /*这里先置为0*/ + task->tss.ecx = 0; + task->tss.edx = 0; + task->tss.ebx = 0; + task->tss.ebp = 0; + task->tss.esi = 0; + task->tss.edi = 0; + task->tss.es = 0; + task->tss.ds = 0; + task->tss.fs = 0; + task->tss.gs = 0; + task->tss.iomap = 0x40000000; + task->tss.ss0 = 0; + return task; + } + } + return 0; /*全部正在使用*/ +} + +void task_run(struct TASK *task, int level, int priority) +{ + if (level < 0) { + level = task->level; /*不改变LEVEL */ + } + if (priority > 0) { + task->priority = priority; + } + if (task->flags == 2 && task->level != level) { + /*改变活动中的LEVEL */ + task_remove(task); /*这里执行之后flag的值会变为1,于是下面的if语句块也会被执行*/ + } + if (task->flags != 2) { + /*从休眠状态唤醒的情形*/ + task->level = level; + task_add(task); + } + taskctl->lv_change = 1; /*下次任务切换时检查LEVEL */ + return; +} + +void task_sleep(struct TASK *task) +{ + struct TASK *now_task; + if (task->flags == 2) { + /*如果处于活动状态*/ + now_task = task_now(); + task_remove(task); /*执行此语句的话flags将变为1 */ + if (task == now_task) { + /*如果是让自己休眠,则需要进行任务切换*/ + task_switchsub(); + now_task = task_now(); /*在设定后获取当前任务的值*/ + farjmp(0, now_task->sel); + } + } + return; +} + + +void task_switch(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + struct TASK *new_task, *now_task = tl->tasks[tl->now]; + tl->now++; + if (tl->now == tl->running) { + tl->now = 0; + } + if (taskctl->lv_change != 0) { + task_switchsub(); + tl = &taskctl->level[taskctl->now_lv]; + } + new_task = tl->tasks[tl->now]; + timer_settime(task_timer, new_task->priority); + if (new_task != now_task) { + farjmp(0, new_task->sel); + } + return; +} diff --git a/28_day/haribote/naskfunc.nas b/28_day/haribote/naskfunc.nas new file mode 100644 index 0000000..a45775d --- /dev/null +++ b/28_day/haribote/naskfunc.nas @@ -0,0 +1,291 @@ +; naskfunc +; TAB=4 + +[FORMAT "WCOFF"] ; 制作目标文件的模式 +[INSTRSET "i486p"] ; 使用到486为止的指令 +[BITS 32] ; 3制作32位模式用的机器语言 +[FILE "naskfunc.nas"] ; 文件名 + + GLOBAL _io_hlt, _io_cli, _io_sti, _io_stihlt + GLOBAL _io_in8, _io_in16, _io_in32 + GLOBAL _io_out8, _io_out16, _io_out32 + GLOBAL _io_load_eflags, _io_store_eflags + GLOBAL _load_gdtr, _load_idtr + GLOBAL _load_cr0, _store_cr0 + GLOBAL _load_tr + GLOBAL _asm_inthandler20, _asm_inthandler21 + GLOBAL _asm_inthandler2c, _asm_inthandler0c + GLOBAL _asm_inthandler0d, _asm_end_app + GLOBAL _memtest_sub + GLOBAL _farjmp, _farcall + GLOBAL _asm_hrb_api, _start_app + EXTERN _inthandler20, _inthandler21 + EXTERN _inthandler2c, _inthandler0d + EXTERN _inthandler0c + EXTERN _hrb_api + +[SECTION .text] + +_io_hlt: ; void io_hlt(void); + HLT + RET + +_io_cli: ; void io_cli(void); + CLI + RET + +_io_sti: ; void io_sti(void); + STI + RET + +_io_stihlt: ; void io_stihlt(void); + STI + HLT + RET + +_io_in8: ; int io_in8(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AL,DX + RET + +_io_in16: ; int io_in16(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AX,DX + RET + +_io_in32: ; int io_in32(int port); + MOV EDX,[ESP+4] ; port + IN EAX,DX + RET + +_io_out8: ; void io_out8(int port, int data); + MOV EDX,[ESP+4] ; port + MOV AL,[ESP+8] ; data + OUT DX,AL + RET + +_io_out16: ; void io_out16(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,AX + RET + +_io_out32: ; void io_out32(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,EAX + RET + +_io_load_eflags: ; int io_load_eflags(void); + PUSHFD ; PUSH EFLAGS + POP EAX + RET + +_io_store_eflags: ; void io_store_eflags(int eflags); + MOV EAX,[ESP+4] + PUSH EAX + POPFD ; POP EFLAGS + RET + +_load_gdtr: ; void load_gdtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LGDT [ESP+6] + RET + +_load_idtr: ; void load_idtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LIDT [ESP+6] + RET + +_load_cr0: ; int load_cr0(void); + MOV EAX,CR0 + RET + +_store_cr0: ; void store_cr0(int cr0); + MOV EAX,[ESP+4] + MOV CR0,EAX + RET + +_load_tr: ; void load_tr(int tr); + LTR [ESP+4] ; tr + RET + +_asm_inthandler20: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler20 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler21: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler21 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler2c: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler2c + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler0c: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0c + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; 在INT 0x0c中也需要这句 + IRETD + +_asm_inthandler0d: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0d + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; INT 0x0d需要这句 + IRETD + +_memtest_sub: ; unsigned int memtest_sub(unsigned int start, unsigned int end) + PUSH EDI ; (由于还要使用EBX, ESI, EDI) + PUSH ESI + PUSH EBX + MOV ESI,0xaa55aa55 ; pat0 = 0xaa55aa55; + MOV EDI,0x55aa55aa ; pat1 = 0x55aa55aa; + MOV EAX,[ESP+12+4] ; i = start; +mts_loop: + MOV EBX,EAX + ADD EBX,0xffc ; p = i + 0xffc; + MOV EDX,[EBX] ; old = *p; + MOV [EBX],ESI ; *p = pat0; + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP EDI,[EBX] ; if (*p != pat1) goto fin; + JNE mts_fin + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP ESI,[EBX] ; if (*p != pat0) goto fin; + JNE mts_fin + MOV [EBX],EDX ; *p = old; + ADD EAX,0x1000 ; i += 0x1000; + CMP EAX,[ESP+12+8] ; if (i <= end) goto mts_loop; + JBE mts_loop + POP EBX + POP ESI + POP EDI + RET +mts_fin: + MOV [EBX],EDX ; *p = old; + POP EBX + POP ESI + POP EDI + RET + +_farjmp: ; void farjmp(int eip, int cs); + JMP FAR [ESP+4] ; eip, cs + RET + +_farcall: ; void farcall(int eip, int cs); + CALL FAR [ESP+4] ; eip, cs + RET + +_asm_hrb_api: + STI + PUSH DS + PUSH ES + PUSHAD ; 用于保存的PUSH + PUSHAD ; 用于向hrb_api传值的PUSH + MOV AX,SS + MOV DS,AX ; 将操作系统用段地址存入DS和ES + MOV ES,AX + CALL _hrb_api + CMP EAX,0 ; 当EAX不为0时程序结束 + JNE _asm_end_app + ADD ESP,32 + POPAD + POP ES + POP DS + IRETD +_asm_end_app: +; EAX为tss.esp0的地址 + MOV ESP,[EAX] + MOV DWORD [EAX+4],0 + POPAD + RET ; 返回cmd_app + +_start_app: ; void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); + PUSHAD ; 将32位寄存器的值全部保存起来 + MOV EAX,[ESP+36] ; 应用程序用EIP + MOV ECX,[ESP+40] ; 应用程序用CS + MOV EDX,[ESP+44] ; 应用程序用ESP + MOV EBX,[ESP+48] ; 应用程序用DS/SS + MOV EBP,[ESP+52] ; tss.esp0的地址 + MOV [EBP ],ESP ; 保存操作系统用ESP + MOV [EBP+4],SS ; 保存操作系统用SS + MOV ES,BX + MOV DS,BX + MOV FS,BX + MOV GS,BX +; 下面调整栈,以免用RETF跳转到应用程序 + OR ECX,3 ; 将应用程序用段号和3进行OR运算 + OR EBX,3 ; 将应用程序用段号和3进行OR运算 + PUSH EBX ; 应用程序的SS + PUSH EDX ; 应用程序的ESP + PUSH ECX ; 应用程序的CS + PUSH EAX ; 应用程序的EIP + RETF +; 应用程序结束后不会回到这里 diff --git a/28_day/haribote/sheet.c b/28_day/haribote/sheet.c new file mode 100644 index 0000000..14aa0ea --- /dev/null +++ b/28_day/haribote/sheet.c @@ -0,0 +1,294 @@ +/* sheet */ + +#include "bootpack.h" + +#define SHEET_USE 1 + +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize) +{ + struct SHTCTL *ctl; + int i; + ctl = (struct SHTCTL *) memman_alloc_4k(memman, sizeof (struct SHTCTL)); + if (ctl == 0) { + goto err; + } + ctl->map = (unsigned char *) memman_alloc_4k(memman, xsize * ysize); + if (ctl->map == 0) { + memman_free_4k(memman, (int) ctl, sizeof (struct SHTCTL)); + goto err; + } + ctl->vram = vram; + ctl->xsize = xsize; + ctl->ysize = ysize; + ctl->top = -1; /* 没有一张SHEET */ + for (i = 0; i < MAX_SHEETS; i++) { + ctl->sheets0[i].flags = 0; /* 标记为未使用 */ + ctl->sheets0[i].ctl = ctl; /* 记录所属*/ + } +err: + return ctl; +} + +struct SHEET *sheet_alloc(struct SHTCTL *ctl) +{ + struct SHEET *sht; + int i; + for (i = 0; i < MAX_SHEETS; i++) { + if (ctl->sheets0[i].flags == 0) { + sht = &ctl->sheets0[i]; + sht->flags = SHEET_USE; /* 标记为正在使用*/ + sht->height = -1; /* 隐藏 */ + sht->task = 0; /*不使用自动关闭功能*/ + return sht; + } + } + return 0; /* 所有的SHEET都处于正在使用状态*/ +} + +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv) +{ + sht->buf = buf; + sht->bxsize = xsize; + sht->bysize = ysize; + sht->col_inv = col_inv; + return; +} + +void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1, sid4, *p;; + unsigned char *buf, sid, *map = ctl->map; + struct SHEET *sht; + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= ctl->top; h++) { + sht = ctl->sheets[h]; + sid = sht - ctl->sheets0; /* 将进行了减法计算的地址作为图层号码使用 */ + buf = sht->buf; + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } + if (by1 > sht->bysize) { by1 = sht->bysize; } + if (sht->col_inv == -1) { + if ((sht->vx0 & 3) == 0 && (bx0 & 3) == 0 && (bx1 & 3) == 0) { + /*无透明色图层专用的高速版(4字节型)*/ + bx1 = (bx1 - bx0) / 4; /* MOV次数*/ + sid4 = sid | sid << 8 | sid << 16 | sid << 24; + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + vx = sht->vx0 + bx0; + p = (int *) &map[vy * ctl->xsize + vx]; + for (bx = 0; bx < bx1; bx++) { + p[bx] = sid4; + } + } + } else { + /*无透明色图层专用的高速版(1字节型)*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + map[vy * ctl->xsize + vx] = sid; + } + } + } + } else { + /*有透明色图层用的普通版*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (buf[by * sht->bxsize + bx] != sht->col_inv) { + map[vy * ctl->xsize + vx] = sid; + } + } + } + } + } + return; +} + +void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0, int h1) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1, bx2, sid4, i, i1, *p, *q, *r; + unsigned char *buf, *vram = ctl->vram, *map = ctl->map, sid; + struct SHEET *sht; + + /* 如果refresh的范围超出了画面则修正 */ + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= h1; h++) { + sht = ctl->sheets[h]; + buf = sht->buf; + sid = sht - ctl->sheets0; + + /* 使用vx0~vy1,对bx0~by1进行倒推 */ + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } /* 处理刷新范围在图层外侧 */ + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } /* 应对不同的重叠方式 */ + if (by1 > sht->bysize) { by1 = sht->bysize; } + if ((sht->vx0 & 3) == 0) { + /* 4字节型*/ + i = (bx0 + 3) / 4; /* bx0除以4(小数进位)*/ + i1 = bx1 / 4; /* bx1除以4(小数舍去)*/ + i1 = i1 - i; + sid4 = sid | sid << 8 | sid << 16 | sid << 24; + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1 && (bx & 3) != 0; bx++) { + /*前面被4除多余的部分逐个字节写入*/ + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + vx = sht->vx0 + bx; + p = (int *) &map[vy * ctl->xsize + vx]; + q = (int *) &vram[vy * ctl->xsize + vx]; + r = (int *) &buf[by * sht->bxsize + bx]; + for (i = 0; i < i1; i++) { + /* 4的倍数部分*/ + if (p[i] == sid4) { + q[i] = r[i]; /*估计大多数会是这种情况,因此速度会变快*/ + } else { + bx2 = bx + i * 4; + vx = sht->vx0 + bx2; + if (map[vy * ctl->xsize + vx + 0] == sid) { + vram[vy * ctl->xsize + vx + 0] = buf[by * sht->bxsize + bx2 + 0]; + } + if (map[vy * ctl->xsize + vx + 1] == sid) { + vram[vy * ctl->xsize + vx + 1] = buf[by * sht->bxsize + bx2 + 1]; + } + if (map[vy * ctl->xsize + vx + 2] == sid) { + vram[vy * ctl->xsize + vx + 2] = buf[by * sht->bxsize + bx2 + 2]; + } + if (map[vy * ctl->xsize + vx + 3] == sid) { + vram[vy * ctl->xsize + vx + 3] = buf[by * sht->bxsize + bx2 + 3]; + } + } + } + for (bx += i1 * 4; bx < bx1; bx++) { + /*后面被4除多余的部分逐个字节写入*/ + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + } + } else { + /* 1字节型*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + } + } + } + return; +} + +void sheet_updown(struct SHEET *sht, int height) +{ + struct SHTCTL *ctl = sht->ctl; + int h, old = sht->height; /* 存储设置前的高度信息 */ + if (height > ctl->top + 1) { + height = ctl->top + 1; + } + if (height < -1) { + height = -1; + } + sht->height = height;/* 设定高度 */ + + /* 下面主要是进行sheets[]的重新排列 */ + if (old > height) { /* 比以前低 */ + if (height >= 0) { + /* 把中间的往上提 */ + for (h = old; h > height; h--) { + ctl->sheets[h] = ctl->sheets[h - 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1, old); + } else { /* 隐藏 */ + if (ctl->top > old) { + /* 把上面的降下来 */ + for (h = old; h < ctl->top; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + } + ctl->top--; /* 由于显示中的图层减少了一个,所以最上面的图层高度下降 */ + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0, old - 1); + } + } else if (old < height) { /* 比以前高 */ + if (old >= 0) { + /* 把中间的拉下去 */ + for (h = old; h < height; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + } else { /* 由隐藏状态转为显示状态 */ + /* 将已在上面的提上来 */ + for (h = ctl->top; h >= height; h--) { + ctl->sheets[h + 1] = ctl->sheets[h]; + ctl->sheets[h + 1]->height = h + 1; + } + ctl->sheets[height] = sht; + ctl->top++; /* 由于已显示的图层增加了1个,所以最上面的图层高度增加 */ + } + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height, height); /* 按新图层信息重新绘制画面 */ + } + return; +} + +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1) +{ + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面*/ + sheet_refreshsub(sht->ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1, sht->height, sht->height); + } + return; +} + +void sheet_slide(struct SHEET *sht, int vx0, int vy0) +{ + struct SHTCTL *ctl = sht->ctl; + int old_vx0 = sht->vx0, old_vy0 = sht->vy0; + sht->vx0 = vx0; + sht->vy0 = vy0; + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面 */ + sheet_refreshmap(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0); + sheet_refreshmap(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height); + sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0, sht->height - 1); + sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height, sht->height); + } + return; +} + +void sheet_free(struct SHEET *sht) +{ + if (sht->height >= 0) { + sheet_updown(sht, -1); /* 如果处于显示状态,则先设定为隐藏 */ + } + sht->flags = 0; /* "未使用"标志 */ + return; +} diff --git a/28_day/haribote/timer.c b/28_day/haribote/timer.c new file mode 100644 index 0000000..9018ac8 --- /dev/null +++ b/28_day/haribote/timer.c @@ -0,0 +1,169 @@ +/* 定时器 */ + +#include "bootpack.h" + +#define PIT_CTRL 0x0043 +#define PIT_CNT0 0x0040 + +struct TIMERCTL timerctl; + +#define TIMER_FLAGS_ALLOC 1 /* 已配置状态 */ +#define TIMER_FLAGS_USING 2 /* 定时器运行中 */ + +void init_pit(void) +{ + int i; + struct TIMER *t; + io_out8(PIT_CTRL, 0x34); + io_out8(PIT_CNT0, 0x9c); + io_out8(PIT_CNT0, 0x2e); + timerctl.count = 0; + for (i = 0; i < MAX_TIMER; i++) { + timerctl.timers0[i].flags = 0; /* 没有使用 */ + } + t = timer_alloc(); /* 取得一个 */ + t->timeout = 0xffffffff; + t->flags = TIMER_FLAGS_USING; + t->next = 0; /* 末尾 */ + timerctl.t0 = t; /* 因为现在只有哨兵,所以他就在最前面*/ + timerctl.next = 0xffffffff; /* 因为只有哨兵,所以下一个超时时刻就是哨兵的时刻 */ + return; +} + +struct TIMER *timer_alloc(void) +{ + int i; + for (i = 0; i < MAX_TIMER; i++) { + if (timerctl.timers0[i].flags == 0) { + timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; + timerctl.timers0[i].flags2 = 0; + return &timerctl.timers0[i]; + } + } + return 0; /* 没找到 */ +} + +void timer_free(struct TIMER *timer) +{ + timer->flags = 0; /* 未使用 */ + return; +} + +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data) +{ + timer->fifo = fifo; + timer->data = data; + return; +} + +void timer_settime(struct TIMER *timer, unsigned int timeout) +{ + int e; + struct TIMER *t, *s; + timer->timeout = timeout + timerctl.count; + timer->flags = TIMER_FLAGS_USING; + e = io_load_eflags(); + io_cli(); + t = timerctl.t0; + if (timer->timeout <= t->timeout) { + /* 插入最前面的情况 */ + timerctl.t0 = timer; + timer->next = t; /* 下面是设定t */ + timerctl.next = timer->timeout; + io_store_eflags(e); + return; + } + for (;;) { + s = t; + t = t->next; + if (timer->timeout <= t->timeout) { + /* 插入s和t之间的情况 */ + s->next = timer; /* s下一个是timer */ + timer->next = t; /* timer的下一个是t */ + io_store_eflags(e); + return; + } + } +} + +void inthandler20(int *esp) +{ + struct TIMER *timer; + char ts = 0; + io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00接收信号结束的信息通知给PIC */ + timerctl.count++; + if (timerctl.next > timerctl.count) { + return; + } + timer = timerctl.t0; /* 首先把最前面的地址赋给timer */ + for (;;) { + /* 因为timers的定时器都处于运行状态,所以不确认flags */ + if (timer->timeout > timerctl.count) { + break; + } + /* 超时 */ + timer->flags = TIMER_FLAGS_ALLOC; + if (timer != task_timer) { + fifo32_put(timer->fifo, timer->data); + } else { + ts = 1; /* mt_timer超时*/ + } + timer = timer->next; /* 将下一个定时器的地址赋给timer*/ + } + timerctl.t0 = timer; + timerctl.next = timer->timeout; + if (ts != 0) { + task_switch(); + } + return; +} + +int timer_cancel(struct TIMER *timer) +{ + int e; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + if (timer->flags == TIMER_FLAGS_USING) { /*是否需要取消?*/ + if (timer == timerctl.t0) { + /*第一个定时器的取消处理*/ + t = timer->next; + timerctl.t0 = t; + timerctl.next = t->timeout; + } else { + /*非第一个定时器的取消处理*/ + /*找到timer前一个定时器*/ + t = timerctl.t0; + for (;;) { + if (t->next == timer) { + break; + } + t = t->next; + } + t->next = timer->next; + /*将之前“timer的下一个”指向“timer的下一个”*/ + } + timer->flags = TIMER_FLAGS_ALLOC; + io_store_eflags(e); + return 1; /*取消处理成功*/ + } + io_store_eflags(e); + return 0; /*不需要取消处理*/ +} + +void timer_cancelall(struct FIFO32 *fifo) +{ + int e, i; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + for (i = 0; i < MAX_TIMER; i++) { + t = &timerctl.timers0[i]; + if (t->flags != 0 && t->flags2 != 0 && t->fifo == fifo) { + timer_cancel(t); + timer_free(t); + } + } + io_store_eflags(e); + return; +} diff --git a/28_day/haribote/window.c b/28_day/haribote/window.c new file mode 100644 index 0000000..4d70578 --- /dev/null +++ b/28_day/haribote/window.c @@ -0,0 +1,118 @@ +/* 窗口相关函数 */ + +#include "bootpack.h" + +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act) +{ + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, xsize - 1, 0 ); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, xsize - 2, 1 ); + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, 0, ysize - 1); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, 1, ysize - 2); + boxfill8(buf, xsize, COL8_848484, xsize - 2, 1, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, xsize - 1, 0, xsize - 1, ysize - 1); + boxfill8(buf, xsize, COL8_C6C6C6, 2, 2, xsize - 3, ysize - 3); + boxfill8(buf, xsize, COL8_848484, 1, ysize - 2, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, 0, ysize - 1, xsize - 1, ysize - 1); + make_wtitle8(buf, xsize, title, act); + return; +} + +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act) +{ + static char closebtn[14][16] = { + "OOOOOOOOOOOOOOO@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQQQ@@QQQQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "O$$$$$$$$$$$$$$@", + "@@@@@@@@@@@@@@@@" + }; + int x, y; + char c, tc, tbc; + if (act != 0) { + tc = COL8_FFFFFF; + tbc = COL8_000084; + } else { + tc = COL8_C6C6C6; + tbc = COL8_848484; + } + boxfill8(buf, xsize, tbc, 3, 3, xsize - 4, 20); + putfonts8_asc(buf, xsize, 24, 4, tc, title); + for (y = 0; y < 14; y++) { + for (x = 0; x < 16; x++) { + c = closebtn[y][x]; + if (c == '@') { + c = COL8_000000; + } else if (c == '$') { + c = COL8_848484; + } else if (c == 'Q') { + c = COL8_C6C6C6; + } else { + c = COL8_FFFFFF; + } + buf[(5 + y) * xsize + (xsize - 21 + x)] = c; + } + } + return; +} + +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l) +{ + boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15); + putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); + sheet_refresh(sht, x, y, x + l * 8, y + 16); + return; +} + +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c) +{ + int x1 = x0 + sx, y1 = y0 + sy; + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3); + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1); + boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0); + return; +} + +void change_wtitle8(struct SHEET *sht, char act) +{ + int x, y, xsize = sht->bxsize; + char c, tc_new, tbc_new, tc_old, tbc_old, *buf = sht->buf; + if (act != 0) { + tc_new = COL8_FFFFFF; + tbc_new = COL8_000084; + tc_old = COL8_C6C6C6; + tbc_old = COL8_848484; + } else { + tc_new = COL8_C6C6C6; + tbc_new = COL8_848484; + tc_old = COL8_FFFFFF; + tbc_old = COL8_000084; + } + for (y = 3; y <= 20; y++) { + for (x = 3; x <= xsize - 4; x++) { + c = buf[y * xsize + x]; + if (c == tc_old && x <= xsize - 22) { + c = tc_new; + } else if (c == tbc_old) { + c = tbc_new; + } + buf[y * xsize + x] = c; + } + } + sheet_refresh(sht, 3, 3, xsize, 21); + return; +} diff --git a/28_day/hello3/!cons_9x.bat b/28_day/hello3/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/hello3/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/hello3/!cons_nt.bat b/28_day/hello3/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/hello3/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/hello3/Makefile b/28_day/hello3/Makefile new file mode 100644 index 0000000..436f686 --- /dev/null +++ b/28_day/hello3/Makefile @@ -0,0 +1,5 @@ +APP = hello3 +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/28_day/hello3/hello3.c b/28_day/hello3/hello3.c new file mode 100644 index 0000000..f71cedf --- /dev/null +++ b/28_day/hello3/hello3.c @@ -0,0 +1,11 @@ +#include "apilib.h" + +void HariMain(void) +{ + api_putchar('h'); + api_putchar('e'); + api_putchar('l'); + api_putchar('l'); + api_putchar('o'); + api_end(); +} diff --git a/28_day/hello3/make.bat b/28_day/hello3/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/hello3/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/hello4/!cons_9x.bat b/28_day/hello4/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/hello4/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/hello4/!cons_nt.bat b/28_day/hello4/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/hello4/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/hello4/Makefile b/28_day/hello4/Makefile new file mode 100644 index 0000000..f4cb8d2 --- /dev/null +++ b/28_day/hello4/Makefile @@ -0,0 +1,5 @@ +APP = hello4 +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/28_day/hello4/hello4.c b/28_day/hello4/hello4.c new file mode 100644 index 0000000..ec04384 --- /dev/null +++ b/28_day/hello4/hello4.c @@ -0,0 +1,7 @@ +#include "apilib.h" + +void HariMain(void) +{ + api_putstr0("hello, world\n"); + api_end(); +} diff --git a/28_day/hello4/make.bat b/28_day/hello4/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/hello4/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/hello5/!cons_9x.bat b/28_day/hello5/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/hello5/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/hello5/!cons_nt.bat b/28_day/hello5/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/hello5/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/hello5/Makefile b/28_day/hello5/Makefile new file mode 100644 index 0000000..366ff9d --- /dev/null +++ b/28_day/hello5/Makefile @@ -0,0 +1,5 @@ +APP = hello5 +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/28_day/hello5/hello5.nas b/28_day/hello5/hello5.nas new file mode 100644 index 0000000..ee62330 --- /dev/null +++ b/28_day/hello5/hello5.nas @@ -0,0 +1,20 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "hello5.nas"] + + GLOBAL _HariMain + +[SECTION .text] + +_HariMain: + MOV EDX,2 + MOV EBX,msg + INT 0x40 + MOV EDX,4 + INT 0x40 + +[SECTION .data] + +msg: + DB "hello, world", 0x0a, 0 diff --git a/28_day/hello5/make.bat b/28_day/hello5/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/hello5/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/lines/!cons_9x.bat b/28_day/lines/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/lines/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/lines/!cons_nt.bat b/28_day/lines/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/lines/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/lines/Makefile b/28_day/lines/Makefile new file mode 100644 index 0000000..45a6aad --- /dev/null +++ b/28_day/lines/Makefile @@ -0,0 +1,5 @@ +APP = lines +STACK = 1k +MALLOC = 48k + +include ../app_make.txt diff --git a/28_day/lines/lines.c b/28_day/lines/lines.c new file mode 100644 index 0000000..5217faa --- /dev/null +++ b/28_day/lines/lines.c @@ -0,0 +1,22 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win, i; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "lines"); + for (i = 0; i < 8; i++) { + api_linewin(win + 1, 8, 26, 77, i * 9 + 26, i); + api_linewin(win + 1, 88, 26, i * 9 + 88, 89, i); + } + api_refreshwin(win, 6, 26, 154, 90); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_closewin(win); + api_end(); +} diff --git a/28_day/lines/make.bat b/28_day/lines/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/lines/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/make.bat b/28_day/make.bat new file mode 100644 index 0000000..e489766 --- /dev/null +++ b/28_day/make.bat @@ -0,0 +1 @@ +..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/noodle/!cons_9x.bat b/28_day/noodle/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/noodle/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/noodle/!cons_nt.bat b/28_day/noodle/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/noodle/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/noodle/Makefile b/28_day/noodle/Makefile new file mode 100644 index 0000000..6ec85b8 --- /dev/null +++ b/28_day/noodle/Makefile @@ -0,0 +1,5 @@ +APP = noodle +STACK = 1k +MALLOC = 40k + +include ../app_make.txt diff --git a/28_day/noodle/make.bat b/28_day/noodle/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/noodle/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/noodle/noodle.c b/28_day/noodle/noodle.c new file mode 100644 index 0000000..108d148 --- /dev/null +++ b/28_day/noodle/noodle.c @@ -0,0 +1,32 @@ +#include +#include "apilib.h" + +void HariMain(void) +{ + char *buf, s[12]; + int win, timer, sec = 0, min = 0, hou = 0; + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "noodle"); + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (;;) { + sprintf(s, "%5d:%02d:%02d", hou, min, sec); + api_boxfilwin(win, 28, 27, 115, 41, 7);/*白色*/ + api_putstrwin(win, 28, 27, 0, 11, s); /*黑色*/ + api_settimer(timer, 100); /* 1秒 */ + if (api_getkey(1) != 128) { + break; + } + sec++; + if (sec == 60) { + sec = 0; + min++; + if (min == 60) { + min = 0; + hou++; + } + } + } + api_end(); +} diff --git a/28_day/star1/!cons_9x.bat b/28_day/star1/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/star1/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/star1/!cons_nt.bat b/28_day/star1/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/star1/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/star1/Makefile b/28_day/star1/Makefile new file mode 100644 index 0000000..ae4cd72 --- /dev/null +++ b/28_day/star1/Makefile @@ -0,0 +1,5 @@ +APP = star1 +STACK = 1k +MALLOC = 47k + +include ../app_make.txt diff --git a/28_day/star1/make.bat b/28_day/star1/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/star1/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/star1/star1.c b/28_day/star1/star1.c new file mode 100644 index 0000000..93241a8 --- /dev/null +++ b/28_day/star1/star1.c @@ -0,0 +1,18 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "star1"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + api_point(win, 75, 59, 3);/*黄色*/ + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/28_day/stars/!cons_9x.bat b/28_day/stars/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/stars/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/stars/!cons_nt.bat b/28_day/stars/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/stars/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/stars/Makefile b/28_day/stars/Makefile new file mode 100644 index 0000000..899cc8f --- /dev/null +++ b/28_day/stars/Makefile @@ -0,0 +1,5 @@ +APP = stars +STACK = 1k +MALLOC = 47k + +include ../app_make.txt diff --git a/28_day/stars/make.bat b/28_day/stars/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/stars/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/stars/stars.c b/28_day/stars/stars.c new file mode 100644 index 0000000..19c54e5 --- /dev/null +++ b/28_day/stars/stars.c @@ -0,0 +1,24 @@ +#include "apilib.h" + +int rand(void); /*产生0~32767之间的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win, x, y, 3);/*黄色*/ + } + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/28_day/stars2/!cons_9x.bat b/28_day/stars2/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/stars2/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/stars2/!cons_nt.bat b/28_day/stars2/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/stars2/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/stars2/Makefile b/28_day/stars2/Makefile new file mode 100644 index 0000000..77c18cd --- /dev/null +++ b/28_day/stars2/Makefile @@ -0,0 +1,5 @@ +APP = stars2 +STACK = 1k +MALLOC = 47k + +include ../app_make.txt diff --git a/28_day/stars2/make.bat b/28_day/stars2/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/stars2/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/stars2/stars2.c b/28_day/stars2/stars2.c new file mode 100644 index 0000000..6c63c19 --- /dev/null +++ b/28_day/stars2/stars2.c @@ -0,0 +1,25 @@ +#include "apilib.h" + +int rand(void); /*产生0~32767的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars2"); + api_boxfilwin(win + 1, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win + 1, x, y, 3);/*黄色*/ + } + api_refreshwin(win, 6, 26, 144, 94); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/28_day/walk/!cons_9x.bat b/28_day/walk/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/walk/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/walk/!cons_nt.bat b/28_day/walk/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/walk/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/walk/Makefile b/28_day/walk/Makefile new file mode 100644 index 0000000..641c368 --- /dev/null +++ b/28_day/walk/Makefile @@ -0,0 +1,5 @@ +APP = walk +STACK = 1k +MALLOC = 48k + +include ../app_make.txt diff --git a/28_day/walk/make.bat b/28_day/walk/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/walk/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/walk/walk.c b/28_day/walk/walk.c new file mode 100644 index 0000000..4772f8a --- /dev/null +++ b/28_day/walk/walk.c @@ -0,0 +1,26 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "walk"); + api_boxfilwin(win, 4, 24, 155, 95, 0);/*黑色*/ + x = 76; + y = 56; + api_putstrwin(win, x, y, 3, 1, "*");/*黄色*/ + for (;;) { + i = api_getkey(1); + api_putstrwin(win, x, y, 0 , 1, "*"); /*用黑色擦除*/ + if (i == '4' && x > 4) { x -= 8; } + if (i == '6' && x < 148) { x += 8; } + if (i == '8' && y > 24) { y -= 8; } + if (i == '2' && y < 80) { y += 8; } + if (i == 0x0a) { break; } /*按回车键结束*/ + api_putstrwin(win, x, y, 3 , 1, "*");/*黄色*/ + } + api_closewin(win); + api_end(); +} diff --git a/28_day/winhelo/!cons_9x.bat b/28_day/winhelo/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/winhelo/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/winhelo/!cons_nt.bat b/28_day/winhelo/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/winhelo/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/winhelo/Makefile b/28_day/winhelo/Makefile new file mode 100644 index 0000000..fe2c669 --- /dev/null +++ b/28_day/winhelo/Makefile @@ -0,0 +1,5 @@ +APP = winhelo +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/28_day/winhelo/make.bat b/28_day/winhelo/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/winhelo/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/winhelo/winhelo.c b/28_day/winhelo/winhelo.c new file mode 100644 index 0000000..8059d36 --- /dev/null +++ b/28_day/winhelo/winhelo.c @@ -0,0 +1,15 @@ +#include "apilib.h" + +char buf[150 * 50]; + +void HariMain(void) +{ + int win; + win = api_openwin(buf, 150, 50, -1, "hello"); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/28_day/winhelo2/!cons_9x.bat b/28_day/winhelo2/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/winhelo2/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/winhelo2/!cons_nt.bat b/28_day/winhelo2/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/winhelo2/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/winhelo2/Makefile b/28_day/winhelo2/Makefile new file mode 100644 index 0000000..df62c78 --- /dev/null +++ b/28_day/winhelo2/Makefile @@ -0,0 +1,5 @@ +APP = winhelo2 +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/28_day/winhelo2/make.bat b/28_day/winhelo2/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/winhelo2/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/winhelo2/winhelo2.c b/28_day/winhelo2/winhelo2.c new file mode 100644 index 0000000..2937402 --- /dev/null +++ b/28_day/winhelo2/winhelo2.c @@ -0,0 +1,17 @@ +#include "apilib.h" + +char buf[150 * 50]; + +void HariMain(void) +{ + int win; + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 3); /*黄色*/ + api_putstrwin(win, 28, 28, 0 /*黑色*/, 12, "hello, world"); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/28_day/winhelo3/!cons_9x.bat b/28_day/winhelo3/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/winhelo3/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/winhelo3/!cons_nt.bat b/28_day/winhelo3/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/winhelo3/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/winhelo3/Makefile b/28_day/winhelo3/Makefile new file mode 100644 index 0000000..719b23a --- /dev/null +++ b/28_day/winhelo3/Makefile @@ -0,0 +1,5 @@ +APP = winhelo3 +STACK = 1k +MALLOC = 40k + +include ../app_make.txt diff --git a/28_day/winhelo3/make.bat b/28_day/winhelo3/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/winhelo3/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/winhelo3/winhelo3.c b/28_day/winhelo3/winhelo3.c new file mode 100644 index 0000000..a1529e5 --- /dev/null +++ b/28_day/winhelo3/winhelo3.c @@ -0,0 +1,19 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win; + + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 6); /*浅蓝色*/ + api_putstrwin(win, 28, 28, 0 , 12, "hello, world");/*黑色*/ + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} From 6bd4307e951641e2bbfa6af44ab4df4118ce267d Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 18 May 2016 10:52:21 +0800 Subject: [PATCH 45/83] =?UTF-8?q?alloca=EF=BC=881=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 28_day/Makefile | 11 ++++++++++- 28_day/sosu/!cons_9x.bat | 1 + 28_day/sosu/!cons_nt.bat | 1 + 28_day/sosu/Makefile | 5 +++++ 28_day/sosu/make.bat | 1 + 28_day/sosu/sosu.c | 24 ++++++++++++++++++++++++ 28_day/sosu2/!cons_9x.bat | 1 + 28_day/sosu2/!cons_nt.bat | 1 + 28_day/sosu2/Makefile | 5 +++++ 28_day/sosu2/make.bat | 1 + 28_day/sosu2/sosu2.c | 24 ++++++++++++++++++++++++ 28_day/sosu3/!cons_9x.bat | 1 + 28_day/sosu3/!cons_nt.bat | 1 + 28_day/sosu3/Makefile | 5 +++++ 28_day/sosu3/make.bat | 1 + 28_day/sosu3/sosu3.c | 26 ++++++++++++++++++++++++++ 16 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 28_day/sosu/!cons_9x.bat create mode 100644 28_day/sosu/!cons_nt.bat create mode 100644 28_day/sosu/Makefile create mode 100644 28_day/sosu/make.bat create mode 100644 28_day/sosu/sosu.c create mode 100644 28_day/sosu2/!cons_9x.bat create mode 100644 28_day/sosu2/!cons_nt.bat create mode 100644 28_day/sosu2/Makefile create mode 100644 28_day/sosu2/make.bat create mode 100644 28_day/sosu2/sosu2.c create mode 100644 28_day/sosu3/!cons_9x.bat create mode 100644 28_day/sosu3/!cons_nt.bat create mode 100644 28_day/sosu3/Makefile create mode 100644 28_day/sosu3/make.bat create mode 100644 28_day/sosu3/sosu3.c diff --git a/28_day/Makefile b/28_day/Makefile index 23e155c..2d22dbf 100644 --- a/28_day/Makefile +++ b/28_day/Makefile @@ -19,7 +19,8 @@ haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ winhelo/winhelo.hrb winhelo2/winhelo2.hrb winhelo3/winhelo3.hrb \ star1/star1.hrb stars/stars.hrb stars2/stars2.hrb \ lines/lines.hrb walk/walk.hrb noodle/noodle.hrb \ - beepdown/beepdown.hrb color/color.hrb color2/color2.hrb + beepdown/beepdown.hrb color/color.hrb color2/color2.hrb \ + sosu/sosu.hrb sosu3/sosu3.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:haribote/ipl10.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ @@ -41,6 +42,8 @@ haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ copy from:beepdown/beepdown.hrb to:@: \ copy from:color/color.hrb to:@: \ copy from:color2/color2.hrb to:@: \ + copy from:sosu/sosu.hrb to:@: \ + copy from:sosu3/sosu3.hrb to:@: \ imgout:haribote.img #命令 @@ -73,6 +76,8 @@ full : $(MAKE) -C beepdown $(MAKE) -C color $(MAKE) -C color2 + $(MAKE) -C sosu + $(MAKE) -C sosu3 $(MAKE) haribote.img run_full : @@ -114,6 +119,8 @@ clean_full : $(MAKE) -C beepdown clean $(MAKE) -C color clean $(MAKE) -C color2 clean + $(MAKE) -C sosu clean + $(MAKE) -C sosu3 clean src_only_full : $(MAKE) -C haribote src_only @@ -134,6 +141,8 @@ src_only_full : $(MAKE) -C beepdown src_only $(MAKE) -C color src_only $(MAKE) -C color2 src_only + $(MAKE) -C sosu src_only + $(MAKE) -C sosu3 src_only -$(DEL) haribote.img refresh : diff --git a/28_day/sosu/!cons_9x.bat b/28_day/sosu/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/sosu/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/sosu/!cons_nt.bat b/28_day/sosu/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/sosu/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/sosu/Makefile b/28_day/sosu/Makefile new file mode 100644 index 0000000..de7b705 --- /dev/null +++ b/28_day/sosu/Makefile @@ -0,0 +1,5 @@ +APP = sosu +STACK = 2k +MALLOC = 0k + +include ../app_make.txt diff --git a/28_day/sosu/make.bat b/28_day/sosu/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/sosu/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/sosu/sosu.c b/28_day/sosu/sosu.c new file mode 100644 index 0000000..6b9a997 --- /dev/null +++ b/28_day/sosu/sosu.c @@ -0,0 +1,24 @@ +#include +#include "apilib.h" + +#define MAX 1000 + +void HariMain(void) +{ + char flag[MAX], s[8]; + int i, j; + for (i = 0; i < MAX; i++) { + flag[i] = 0; + } + for (i = 2; i < MAX; i++) { + if (flag[i] == 0) { + /*没有标记的为质数*/ + sprintf(s, "%d ", i); + api_putstr0(s); + for (j = i * 2; j < MAX; j += i) { + flag[j] = 1; /*给它的倍数做上标记*/ + } + } + } + api_end(); +} diff --git a/28_day/sosu2/!cons_9x.bat b/28_day/sosu2/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/sosu2/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/sosu2/!cons_nt.bat b/28_day/sosu2/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/sosu2/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/sosu2/Makefile b/28_day/sosu2/Makefile new file mode 100644 index 0000000..d97a733 --- /dev/null +++ b/28_day/sosu2/Makefile @@ -0,0 +1,5 @@ +APP = sosu2 +STACK = 11k +MALLOC = 0k + +include ../app_make.txt diff --git a/28_day/sosu2/make.bat b/28_day/sosu2/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/sosu2/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/sosu2/sosu2.c b/28_day/sosu2/sosu2.c new file mode 100644 index 0000000..381e436 --- /dev/null +++ b/28_day/sosu2/sosu2.c @@ -0,0 +1,24 @@ +#include +#include "apilib.h" + +#define MAX 10000 + +void HariMain(void) +{ + char flag[MAX], s[8]; + int i, j; + for (i = 0; i < MAX; i++) { + flag[i] = 0; + } + for (i = 2; i < MAX; i++) { + if (flag[i] == 0) { + /*没有标记的为质数*/ + sprintf(s, "%d ", i); + api_putstr0(s); + for (j = i * 2; j < MAX; j += i) { + flag[j] = 1; /*给它的倍数做上标记*/ + } + } + } + api_end(); +} diff --git a/28_day/sosu3/!cons_9x.bat b/28_day/sosu3/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/sosu3/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/sosu3/!cons_nt.bat b/28_day/sosu3/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/sosu3/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/sosu3/Makefile b/28_day/sosu3/Makefile new file mode 100644 index 0000000..a7e9900 --- /dev/null +++ b/28_day/sosu3/Makefile @@ -0,0 +1,5 @@ +APP = sosu3 +STACK = 1k +MALLOC = 42k + +include ../app_make.txt diff --git a/28_day/sosu3/make.bat b/28_day/sosu3/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/sosu3/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/sosu3/sosu3.c b/28_day/sosu3/sosu3.c new file mode 100644 index 0000000..db4527b --- /dev/null +++ b/28_day/sosu3/sosu3.c @@ -0,0 +1,26 @@ +#include +#include "apilib.h" + +#define MAX 10000 + +void HariMain(void) +{ + char *flag, s[8]; + int i, j; + api_initmalloc(); + flag = api_malloc(MAX); + for (i = 0; i < MAX; i++) { + flag[i] = 0; + } + for (i = 2; i < MAX; i++) { + if (flag[i] == 0) { + /*没有标记的为质数*/ + sprintf(s, "%d ", i); + api_putstr0(s); + for (j = i * 2; j < MAX; j += i) { + flag[j] = 1; /*给它的倍数做上标记*/ + } + } + } + api_end(); +} From 1bcf500c142422bb33af20087a7b52d46d02ce1e Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 18 May 2016 10:54:21 +0800 Subject: [PATCH 46/83] bug fix --- 27_day/apilib/Makefile | 8 ++++---- 28_day/apilib/Makefile | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/27_day/apilib/Makefile b/27_day/apilib/Makefile index e93248b..35ff0ac 100644 --- a/27_day/apilib/Makefile +++ b/27_day/apilib/Makefile @@ -21,22 +21,22 @@ GOLIB = $(TOOLPATH)golib00.exe COPY = copy DEL = del -# ftHg +#默认动作 default : $(MAKE) apilib.lib -# t@CK +#库生成规则 apilib.lib : Makefile $(OBJS_API) $(GOLIB) $(OBJS_API) out:apilib.lib -# ʋK +#文件生成规则 %.obj : %.nas Makefile $(NASK) $*.nas $*.obj $*.lst -# R}h +#命令 clean : -$(DEL) *.lst diff --git a/28_day/apilib/Makefile b/28_day/apilib/Makefile index e93248b..35ff0ac 100644 --- a/28_day/apilib/Makefile +++ b/28_day/apilib/Makefile @@ -21,22 +21,22 @@ GOLIB = $(TOOLPATH)golib00.exe COPY = copy DEL = del -# ftHg +#默认动作 default : $(MAKE) apilib.lib -# t@CK +#库生成规则 apilib.lib : Makefile $(OBJS_API) $(GOLIB) $(OBJS_API) out:apilib.lib -# ʋK +#文件生成规则 %.obj : %.nas Makefile $(NASK) $*.nas $*.obj $*.lst -# R}h +#命令 clean : -$(DEL) *.lst From 7b5d69c7c85779d0ba808f321767fb7b82a7db7b Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 18 May 2016 11:02:51 +0800 Subject: [PATCH 47/83] =?UTF-8?q?alloca=EF=BC=882=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 28_day/Makefile | 6 +++++- 28_day/apilib/Makefile | 3 ++- 28_day/apilib/alloca.nas | 13 +++++++++++++ 28_day/winhelo/Makefile | 2 +- 28_day/winhelo/winhelo.c | 4 ++-- 28_day/winhelo2/Makefile | 2 +- 28_day/winhelo2/winhelo2.c | 4 ++-- 7 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 28_day/apilib/alloca.nas diff --git a/28_day/Makefile b/28_day/Makefile index 2d22dbf..732a74d 100644 --- a/28_day/Makefile +++ b/28_day/Makefile @@ -20,7 +20,7 @@ haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ star1/star1.hrb stars/stars.hrb stars2/stars2.hrb \ lines/lines.hrb walk/walk.hrb noodle/noodle.hrb \ beepdown/beepdown.hrb color/color.hrb color2/color2.hrb \ - sosu/sosu.hrb sosu3/sosu3.hrb + sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:haribote/ipl10.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ @@ -43,6 +43,7 @@ haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ copy from:color/color.hrb to:@: \ copy from:color2/color2.hrb to:@: \ copy from:sosu/sosu.hrb to:@: \ + copy from:sosu2/sosu2.hrb to:@: \ copy from:sosu3/sosu3.hrb to:@: \ imgout:haribote.img @@ -77,6 +78,7 @@ full : $(MAKE) -C color $(MAKE) -C color2 $(MAKE) -C sosu + $(MAKE) -C sosu2 $(MAKE) -C sosu3 $(MAKE) haribote.img @@ -120,6 +122,7 @@ clean_full : $(MAKE) -C color clean $(MAKE) -C color2 clean $(MAKE) -C sosu clean + $(MAKE) -C sosu2 clean $(MAKE) -C sosu3 clean src_only_full : @@ -142,6 +145,7 @@ src_only_full : $(MAKE) -C color src_only $(MAKE) -C color2 src_only $(MAKE) -C sosu src_only + $(MAKE) -C sosu2 src_only $(MAKE) -C sosu3 src_only -$(DEL) haribote.img diff --git a/28_day/apilib/Makefile b/28_day/apilib/Makefile index 35ff0ac..05c00ea 100644 --- a/28_day/apilib/Makefile +++ b/28_day/apilib/Makefile @@ -1,7 +1,8 @@ OBJS_API = api001.obj api002.obj api003.obj api004.obj api005.obj api006.obj \ api007.obj api008.obj api009.obj api010.obj api011.obj api012.obj \ api013.obj api014.obj api015.obj api016.obj api017.obj api018.obj \ - api019.obj api020.obj + api019.obj api020.obj \ + alloca.obj TOOLPATH = ../../z_tools/ INCPATH = ../../z_tools/haribote/ diff --git a/28_day/apilib/alloca.nas b/28_day/apilib/alloca.nas new file mode 100644 index 0000000..b94f8e2 --- /dev/null +++ b/28_day/apilib/alloca.nas @@ -0,0 +1,13 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "alloca.nas"] + + GLOBAL __alloca + +[SECTION .text] + +__alloca: + ADD EAX,-4 + SUB ESP,EAX + JMP DWORD [ESP+EAX] ; 代替RET diff --git a/28_day/winhelo/Makefile b/28_day/winhelo/Makefile index fe2c669..44ac359 100644 --- a/28_day/winhelo/Makefile +++ b/28_day/winhelo/Makefile @@ -1,5 +1,5 @@ APP = winhelo -STACK = 1k +STACK = 8k MALLOC = 0k include ../app_make.txt diff --git a/28_day/winhelo/winhelo.c b/28_day/winhelo/winhelo.c index 8059d36..c36e988 100644 --- a/28_day/winhelo/winhelo.c +++ b/28_day/winhelo/winhelo.c @@ -1,10 +1,10 @@ #include "apilib.h" -char buf[150 * 50]; - void HariMain(void) { int win; + char buf[150 * 50]; + win = api_openwin(buf, 150, 50, -1, "hello"); for (;;) { if (api_getkey(1) == 0x0a) { diff --git a/28_day/winhelo2/Makefile b/28_day/winhelo2/Makefile index df62c78..a1544f5 100644 --- a/28_day/winhelo2/Makefile +++ b/28_day/winhelo2/Makefile @@ -1,5 +1,5 @@ APP = winhelo2 -STACK = 1k +STACK = 8k MALLOC = 0k include ../app_make.txt diff --git a/28_day/winhelo2/winhelo2.c b/28_day/winhelo2/winhelo2.c index 2937402..dfc4ce7 100644 --- a/28_day/winhelo2/winhelo2.c +++ b/28_day/winhelo2/winhelo2.c @@ -1,10 +1,10 @@ #include "apilib.h" -char buf[150 * 50]; - void HariMain(void) { int win; + char buf[150 * 50]; + win = api_openwin(buf, 150, 50, -1, "hello"); api_boxfilwin(win, 8, 36, 141, 43, 3); /*黄色*/ api_putstrwin(win, 28, 28, 0 /*黑色*/, 12, "hello, world"); From 9231ce4a386e43ae1173a75562f47778a03b5ae9 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 18 May 2016 11:31:29 +0800 Subject: [PATCH 48/83] =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=93=8D=E4=BD=9CAPI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 28_day/Makefile | 7 +++- 28_day/apilib.h | 5 +++ 28_day/apilib/Makefile | 4 +-- 28_day/apilib/api021.nas | 16 +++++++++ 28_day/apilib/api022.nas | 14 ++++++++ 28_day/apilib/api023.nas | 18 ++++++++++ 28_day/apilib/api024.nas | 15 ++++++++ 28_day/apilib/api025.nas | 18 ++++++++++ 28_day/haribote/bootpack.h | 7 ++++ 28_day/haribote/console.c | 72 +++++++++++++++++++++++++++++++++++++ 28_day/typeipl/!cons_9x.bat | 1 + 28_day/typeipl/!cons_nt.bat | 1 + 28_day/typeipl/Makefile | 5 +++ 28_day/typeipl/make.bat | 1 + 28_day/typeipl/typeipl.c | 17 +++++++++ 15 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 28_day/apilib/api021.nas create mode 100644 28_day/apilib/api022.nas create mode 100644 28_day/apilib/api023.nas create mode 100644 28_day/apilib/api024.nas create mode 100644 28_day/apilib/api025.nas create mode 100644 28_day/typeipl/!cons_9x.bat create mode 100644 28_day/typeipl/!cons_nt.bat create mode 100644 28_day/typeipl/Makefile create mode 100644 28_day/typeipl/make.bat create mode 100644 28_day/typeipl/typeipl.c diff --git a/28_day/Makefile b/28_day/Makefile index 732a74d..3cd3639 100644 --- a/28_day/Makefile +++ b/28_day/Makefile @@ -20,7 +20,8 @@ haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ star1/star1.hrb stars/stars.hrb stars2/stars2.hrb \ lines/lines.hrb walk/walk.hrb noodle/noodle.hrb \ beepdown/beepdown.hrb color/color.hrb color2/color2.hrb \ - sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb + sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb \ + typeipl/typeipl.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:haribote/ipl10.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ @@ -45,6 +46,7 @@ haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ copy from:sosu/sosu.hrb to:@: \ copy from:sosu2/sosu2.hrb to:@: \ copy from:sosu3/sosu3.hrb to:@: \ + copy from:typeipl/typeipl.hrb to:@: \ imgout:haribote.img #命令 @@ -80,6 +82,7 @@ full : $(MAKE) -C sosu $(MAKE) -C sosu2 $(MAKE) -C sosu3 + $(MAKE) -C typeipl $(MAKE) haribote.img run_full : @@ -124,6 +127,7 @@ clean_full : $(MAKE) -C sosu clean $(MAKE) -C sosu2 clean $(MAKE) -C sosu3 clean + $(MAKE) -C typeipl clean src_only_full : $(MAKE) -C haribote src_only @@ -147,6 +151,7 @@ src_only_full : $(MAKE) -C sosu src_only $(MAKE) -C sosu2 src_only $(MAKE) -C sosu3 src_only + $(MAKE) -C typeipl src_only -$(DEL) haribote.img refresh : diff --git a/28_day/apilib.h b/28_day/apilib.h index 80ec6e0..07b8021 100644 --- a/28_day/apilib.h +++ b/28_day/apilib.h @@ -18,3 +18,8 @@ void api_inittimer(int timer, int data); void api_settimer(int timer, int time); void api_freetimer(int timer); void api_beep(int tone); +int api_fopen(char *fname); +void api_fclose(int fhandle); +void api_fseek(int fhandle, int offset, int mode); +int api_fsize(int fhandle, int mode); +int api_fread(char *buf, int maxsize, int fhandle); diff --git a/28_day/apilib/Makefile b/28_day/apilib/Makefile index 05c00ea..3c35274 100644 --- a/28_day/apilib/Makefile +++ b/28_day/apilib/Makefile @@ -1,8 +1,8 @@ OBJS_API = api001.obj api002.obj api003.obj api004.obj api005.obj api006.obj \ api007.obj api008.obj api009.obj api010.obj api011.obj api012.obj \ api013.obj api014.obj api015.obj api016.obj api017.obj api018.obj \ - api019.obj api020.obj \ - alloca.obj + api019.obj api020.obj api021.obj api022.obj api023.obj api024.obj \ + api025.obj alloca.obj TOOLPATH = ../../z_tools/ INCPATH = ../../z_tools/haribote/ diff --git a/28_day/apilib/api021.nas b/28_day/apilib/api021.nas new file mode 100644 index 0000000..565a037 --- /dev/null +++ b/28_day/apilib/api021.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api021.nas"] + + GLOBAL _api_fopen + +[SECTION .text] + +_api_fopen: ; int api_fopen(char *fname); + PUSH EBX + MOV EDX,21 + MOV EBX,[ESP+8] ; fname + INT 0x40 + POP EBX + RET diff --git a/28_day/apilib/api022.nas b/28_day/apilib/api022.nas new file mode 100644 index 0000000..a21f508 --- /dev/null +++ b/28_day/apilib/api022.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api022.nas"] + + GLOBAL _api_fclose + +[SECTION .text] + +_api_fclose: ; void api_fclose(int fhandle); + MOV EDX,22 + MOV EAX,[ESP+4] ; fhandle + INT 0x40 + RET diff --git a/28_day/apilib/api023.nas b/28_day/apilib/api023.nas new file mode 100644 index 0000000..f34c33b --- /dev/null +++ b/28_day/apilib/api023.nas @@ -0,0 +1,18 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api023.nas"] + + GLOBAL _api_fseek + +[SECTION .text] + +_api_fseek: ; void api_fseek(int fhandle, int offset, int mode); + PUSH EBX + MOV EDX,23 + MOV EAX,[ESP+8] ; fhandle + MOV ECX,[ESP+16] ; mode + MOV EBX,[ESP+12] ; offset + INT 0x40 + POP EBX + RET diff --git a/28_day/apilib/api024.nas b/28_day/apilib/api024.nas new file mode 100644 index 0000000..5352889 --- /dev/null +++ b/28_day/apilib/api024.nas @@ -0,0 +1,15 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api024.nas"] + + GLOBAL _api_fsize + +[SECTION .text] + +_api_fsize: ; int api_fsize(int fhandle, int mode); + MOV EDX,24 + MOV EAX,[ESP+4] ; fhandle + MOV ECX,[ESP+8] ; mode + INT 0x40 + RET diff --git a/28_day/apilib/api025.nas b/28_day/apilib/api025.nas new file mode 100644 index 0000000..9f394d3 --- /dev/null +++ b/28_day/apilib/api025.nas @@ -0,0 +1,18 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api025.nas"] + + GLOBAL _api_fread + +[SECTION .text] + +_api_fread: ; int api_fread(char *buf, int maxsize, int fhandle); + PUSH EBX + MOV EDX,25 + MOV EAX,[ESP+16] ; fhandle + MOV ECX,[ESP+12] ; maxsize + MOV EBX,[ESP+8] ; buf + INT 0x40 + POP EBX + RET diff --git a/28_day/haribote/bootpack.h b/28_day/haribote/bootpack.h index f4ec328..85ee710 100644 --- a/28_day/haribote/bootpack.h +++ b/28_day/haribote/bootpack.h @@ -214,6 +214,8 @@ struct TASK { struct SEGMENT_DESCRIPTOR ldt[2]; struct CONSOLE *cons; int ds_base, cons_stack; + struct FILEHANDLE *fhandle; + int *fat; }; struct TASKLEVEL { int running; /*正在运行的任务数量*/ @@ -248,6 +250,11 @@ struct CONSOLE { int cur_x, cur_y, cur_c; struct TIMER *timer; }; +struct FILEHANDLE { + char *buf; + int size; + int pos; +}; void console_task(struct SHEET *sheet, int memtotal); void cons_putchar(struct CONSOLE *cons, int chr, char move); void cons_newline(struct CONSOLE *cons); diff --git a/28_day/haribote/console.c b/28_day/haribote/console.c index 6ce8fdc..3dd0440 100644 --- a/28_day/haribote/console.c +++ b/28_day/haribote/console.c @@ -9,8 +9,10 @@ void console_task(struct SHEET *sheet, int memtotal) struct TASK *task = task_now(); struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; int i, *fat = (int *) memman_alloc_4k(memman, 4 * 2880); + struct FILEHANDLE fhandle[8]; struct CONSOLE cons; char cmdline[30]; + cons.sht = sheet; cons.cur_x = 8; cons.cur_y = 28; @@ -23,6 +25,11 @@ void console_task(struct SHEET *sheet, int memtotal) timer_settime(cons.timer, 50); } file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); + for (i = 0; i < 8; i++) { + fhandle[i].buf = 0; /*未使用标记*/ + } + task->fhandle = fhandle; + task->fat = fat; /*显示提示符*/ cons_putchar(&cons, '>', 1); @@ -387,6 +394,12 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) sheet_free(sht); /*关闭*/ } } + for (i = 0; i < 8; i++) { /*将未关闭的文件关闭*/ + if (task->fhandle[i].buf != 0) { + memman_free_4k(memman, (int) task->fhandle[i].buf, task->fhandle[i].size); + task->fhandle[i].buf = 0; + } + } timer_cancelall(&task->fifo); memman_free_4k(memman, (int) q, segsiz); } else { @@ -413,6 +426,9 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */ /* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ int i; + struct FILEINFO *finfo; + struct FILEHANDLE *fh; + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; if (edx == 1) { cons_putchar(cons, eax & 0xff, 1); @@ -528,6 +544,62 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int i = io_in8(0x61); io_out8(0x61, (i | 0x03) & 0x0f); } + } else if (edx == 21) { + for (i = 0; i < 8; i++) { + if (task->fhandle[i].buf == 0) { + break; + } + } + fh = &task->fhandle[i]; + reg[7] = 0; + if (i < 8) { + finfo = file_search((char *) ebx + ds_base, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + if (finfo != 0) { + reg[7] = (int) fh; + fh->buf = (char *) memman_alloc_4k(memman, finfo->size); + fh->size = finfo->size; + fh->pos = 0; + file_loadfile(finfo->clustno, finfo->size, fh->buf, task->fat, (char *) (ADR_DISKIMG + 0x003e00)); + } + } + } else if (edx == 22) { + fh = (struct FILEHANDLE *) eax; + memman_free_4k(memman, (int) fh->buf, fh->size); + fh->buf = 0; + } else if (edx == 23) { + fh = (struct FILEHANDLE *) eax; + if (ecx == 0) { + fh->pos = ebx; + } else if (ecx == 1) { + fh->pos += ebx; + } else if (ecx == 2) { + fh->pos = fh->size + ebx; + } + if (fh->pos < 0) { + fh->pos = 0; + } + if (fh->pos > fh->size) { + fh->pos = fh->size; + } + } else if (edx == 24) { + fh = (struct FILEHANDLE *) eax; + if (ecx == 0) { + reg[7] = fh->size; + } else if (ecx == 1) { + reg[7] = fh->pos; + } else if (ecx == 2) { + reg[7] = fh->pos - fh->size; + } + } else if (edx == 25) { + fh = (struct FILEHANDLE *) eax; + for (i = 0; i < ecx; i++) { + if (fh->pos == fh->size) { + break; + } + *((char *) ebx + ds_base + i) = fh->buf[fh->pos]; + fh->pos++; + } + reg[7] = i; } return 0; } diff --git a/28_day/typeipl/!cons_9x.bat b/28_day/typeipl/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/typeipl/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/typeipl/!cons_nt.bat b/28_day/typeipl/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/typeipl/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/typeipl/Makefile b/28_day/typeipl/Makefile new file mode 100644 index 0000000..f5b423e --- /dev/null +++ b/28_day/typeipl/Makefile @@ -0,0 +1,5 @@ +APP = typeipl +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/28_day/typeipl/make.bat b/28_day/typeipl/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/typeipl/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/typeipl/typeipl.c b/28_day/typeipl/typeipl.c new file mode 100644 index 0000000..90a0273 --- /dev/null +++ b/28_day/typeipl/typeipl.c @@ -0,0 +1,17 @@ +#include "apilib.h" + +void HariMain(void) +{ + int fh; + char c; + fh = api_fopen("ipl10.nas"); + if (fh != 0) { + for (;;) { + if (api_fread(&c, 1, fh) == 0) { + break; + } + api_putchar(c); + } + } + api_end(); +} From 86791cd7f4cd939ff8f4f0fcf2befdc78d03d824 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 18 May 2016 11:41:34 +0800 Subject: [PATCH 49/83] =?UTF-8?q?=E5=91=BD=E4=BB=A4=E8=A1=8CAPI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 28_day/Makefile | 6 +++++- 28_day/apilib.h | 1 + 28_day/apilib/Makefile | 2 +- 28_day/apilib/api026.nas | 17 +++++++++++++++++ 28_day/haribote/bootpack.h | 2 +- 28_day/haribote/console.c | 35 ++++++++++++++--------------------- 28_day/type/!cons_9x.bat | 1 + 28_day/type/!cons_nt.bat | 1 + 28_day/type/Makefile | 5 +++++ 28_day/type/make.bat | 1 + 28_day/type/type.c | 23 +++++++++++++++++++++++ 11 files changed, 70 insertions(+), 24 deletions(-) create mode 100644 28_day/apilib/api026.nas create mode 100644 28_day/type/!cons_9x.bat create mode 100644 28_day/type/!cons_nt.bat create mode 100644 28_day/type/Makefile create mode 100644 28_day/type/make.bat create mode 100644 28_day/type/type.c diff --git a/28_day/Makefile b/28_day/Makefile index 3cd3639..046fcf9 100644 --- a/28_day/Makefile +++ b/28_day/Makefile @@ -21,7 +21,7 @@ haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ lines/lines.hrb walk/walk.hrb noodle/noodle.hrb \ beepdown/beepdown.hrb color/color.hrb color2/color2.hrb \ sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb \ - typeipl/typeipl.hrb + typeipl/typeipl.hrb type/type.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:haribote/ipl10.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ @@ -47,6 +47,7 @@ haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ copy from:sosu2/sosu2.hrb to:@: \ copy from:sosu3/sosu3.hrb to:@: \ copy from:typeipl/typeipl.hrb to:@: \ + copy from:type/type.hrb to:@: \ imgout:haribote.img #命令 @@ -83,6 +84,7 @@ full : $(MAKE) -C sosu2 $(MAKE) -C sosu3 $(MAKE) -C typeipl + $(MAKE) -C type $(MAKE) haribote.img run_full : @@ -128,6 +130,7 @@ clean_full : $(MAKE) -C sosu2 clean $(MAKE) -C sosu3 clean $(MAKE) -C typeipl clean + $(MAKE) -C type clean src_only_full : $(MAKE) -C haribote src_only @@ -152,6 +155,7 @@ src_only_full : $(MAKE) -C sosu2 src_only $(MAKE) -C sosu3 src_only $(MAKE) -C typeipl src_only + $(MAKE) -C type src_only -$(DEL) haribote.img refresh : diff --git a/28_day/apilib.h b/28_day/apilib.h index 07b8021..fbf0884 100644 --- a/28_day/apilib.h +++ b/28_day/apilib.h @@ -23,3 +23,4 @@ void api_fclose(int fhandle); void api_fseek(int fhandle, int offset, int mode); int api_fsize(int fhandle, int mode); int api_fread(char *buf, int maxsize, int fhandle); +int api_cmdline(char *buf, int maxsize); diff --git a/28_day/apilib/Makefile b/28_day/apilib/Makefile index 3c35274..b40633b 100644 --- a/28_day/apilib/Makefile +++ b/28_day/apilib/Makefile @@ -2,7 +2,7 @@ OBJS_API = api001.obj api002.obj api003.obj api004.obj api005.obj api006.obj \ api007.obj api008.obj api009.obj api010.obj api011.obj api012.obj \ api013.obj api014.obj api015.obj api016.obj api017.obj api018.obj \ api019.obj api020.obj api021.obj api022.obj api023.obj api024.obj \ - api025.obj alloca.obj + api025.obj api026.obj alloca.obj TOOLPATH = ../../z_tools/ INCPATH = ../../z_tools/haribote/ diff --git a/28_day/apilib/api026.nas b/28_day/apilib/api026.nas new file mode 100644 index 0000000..33bb2f5 --- /dev/null +++ b/28_day/apilib/api026.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api026.nas"] + + GLOBAL _api_cmdline + +[SECTION .text] + +_api_cmdline: ; int api_cmdline(char *buf, int maxsize); + PUSH EBX + MOV EDX,26 + MOV ECX,[ESP+12] ; maxsize + MOV EBX,[ESP+8] ; buf + INT 0x40 + POP EBX + RET diff --git a/28_day/haribote/bootpack.h b/28_day/haribote/bootpack.h index 85ee710..56c12b8 100644 --- a/28_day/haribote/bootpack.h +++ b/28_day/haribote/bootpack.h @@ -216,6 +216,7 @@ struct TASK { int ds_base, cons_stack; struct FILEHANDLE *fhandle; int *fat; + char *cmdline; }; struct TASKLEVEL { int running; /*正在运行的任务数量*/ @@ -264,7 +265,6 @@ void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal); void cmd_mem(struct CONSOLE *cons, int memtotal); void cmd_cls(struct CONSOLE *cons); void cmd_dir(struct CONSOLE *cons); -void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline); void cmd_exit(struct CONSOLE *cons, int *fat); void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal); void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal); diff --git a/28_day/haribote/console.c b/28_day/haribote/console.c index 3dd0440..3d0c70b 100644 --- a/28_day/haribote/console.c +++ b/28_day/haribote/console.c @@ -18,6 +18,7 @@ void console_task(struct SHEET *sheet, int memtotal) cons.cur_y = 28; cons.cur_c = -1; task->cons = &cons; + task->cmdline = cmdline; if (cons.sht != 0) { cons.timer = timer_alloc(); @@ -198,8 +199,6 @@ void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) cmd_cls(cons); } else if ((strcmp(cmdline, "dir") == 0 || strcmp(cmdline, "ls") == 0) && cons->sht != 0) { cmd_dir(cons); - } else if (strncmp(cmdline, "type ", 5) == 0 && cons->sht != 0) { - cmd_type(cons, fat, cmdline); } else if (strcmp(cmdline, "exit") == 0) { cmd_exit(cons, fat); } else if (strncmp(cmdline, "start ", 6) == 0) { @@ -264,25 +263,6 @@ void cmd_dir(struct CONSOLE *cons) return; } -void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline) -{ - struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; - struct FILEINFO *finfo = file_search(cmdline + 5, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); - char *p; - if (finfo != 0) { - /*找到文件的情况*/ - p = (char *) memman_alloc_4k(memman, finfo->size); - file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); - cons_putstr1(cons, p, finfo->size); - memman_free_4k(memman, (int) p, finfo->size); - } else { - /*没有找到文件的情况*/ - cons_putstr0(cons, "File not found.\n"); - } - cons_newline(cons); - return; -} - void cmd_exit(struct CONSOLE *cons, int *fat) { struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; @@ -600,6 +580,19 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int fh->pos++; } reg[7] = i; + } else if (edx == 26) { + i = 0; + for (;;) { + *((char *) ebx + ds_base + i) = task->cmdline[i]; + if (task->cmdline[i] == 0) { + break; + } + if (i >= ecx) { + break; + } + i++; + } + reg[7] = i; } return 0; } diff --git a/28_day/type/!cons_9x.bat b/28_day/type/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/type/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/type/!cons_nt.bat b/28_day/type/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/type/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/type/Makefile b/28_day/type/Makefile new file mode 100644 index 0000000..7314b7b --- /dev/null +++ b/28_day/type/Makefile @@ -0,0 +1,5 @@ +APP = type +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/28_day/type/make.bat b/28_day/type/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/type/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/type/type.c b/28_day/type/type.c new file mode 100644 index 0000000..c6fc99f --- /dev/null +++ b/28_day/type/type.c @@ -0,0 +1,23 @@ +#include "apilib.h" + +void HariMain(void) +{ + int fh; + char c, cmdline[30], *p; + + api_cmdline(cmdline, 30); + for (p = cmdline; *p > ' '; p++) { } /*跳过之前的内容,直到遇到空格*/ + for (; *p == ' '; p++) { } /*跳过空格*/ + fh = api_fopen(p); + if (fh != 0) { + for (;;) { + if (api_fread(&c, 1, fh) == 0) { + break; + } + api_putchar(c); + } + } else { + api_putstr0("File not found.\n"); + } + api_end(); +} From ac8b6b14112ebb76b657838a4cdbcc8438994013 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 18 May 2016 12:43:01 +0800 Subject: [PATCH 50/83] =?UTF-8?q?=E6=97=A5=E6=96=87=E6=96=87=E5=AD=97?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=EF=BC=881=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 28_day/Makefile | 9 +++++++-- 28_day/haribote/bootpack.c | 25 ++++++++++++++++++++++++- 28_day/haribote/bootpack.h | 2 ++ 28_day/haribote/console.c | 23 ++++++++++++++++++++++- 28_day/haribote/graphic.c | 16 +++++++++++++--- 28_day/iroha/!cons_9x.bat | 1 + 28_day/iroha/!cons_nt.bat | 1 + 28_day/iroha/Makefile | 5 +++++ 28_day/iroha/iroha.c | 9 +++++++++ 28_day/iroha/make.bat | 1 + 28_day/nihongo/jpn16v00.bin | Bin 0 -> 311296 bytes 28_day/nihongo/jpn16v00.fnt | Bin 0 -> 58084 bytes 28_day/nihongo/nihongo.fnt | Bin 0 -> 145472 bytes 13 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 28_day/iroha/!cons_9x.bat create mode 100644 28_day/iroha/!cons_nt.bat create mode 100644 28_day/iroha/Makefile create mode 100644 28_day/iroha/iroha.c create mode 100644 28_day/iroha/make.bat create mode 100644 28_day/nihongo/jpn16v00.bin create mode 100644 28_day/nihongo/jpn16v00.fnt create mode 100644 28_day/nihongo/nihongo.fnt diff --git a/28_day/Makefile b/28_day/Makefile index 046fcf9..ae13e61 100644 --- a/28_day/Makefile +++ b/28_day/Makefile @@ -21,7 +21,7 @@ haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ lines/lines.hrb walk/walk.hrb noodle/noodle.hrb \ beepdown/beepdown.hrb color/color.hrb color2/color2.hrb \ sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb \ - typeipl/typeipl.hrb type/type.hrb + typeipl/typeipl.hrb type/type.hrb iroha/iroha.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:haribote/ipl10.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ @@ -48,6 +48,8 @@ haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ copy from:sosu3/sosu3.hrb to:@: \ copy from:typeipl/typeipl.hrb to:@: \ copy from:type/type.hrb to:@: \ + copy from:iroha/iroha.hrb to:@: \ + copy from:nihongo/nihongo.fnt to:@: \ imgout:haribote.img #命令 @@ -85,6 +87,7 @@ full : $(MAKE) -C sosu3 $(MAKE) -C typeipl $(MAKE) -C type + $(MAKE) -C iroha $(MAKE) haribote.img run_full : @@ -131,6 +134,7 @@ clean_full : $(MAKE) -C sosu3 clean $(MAKE) -C typeipl clean $(MAKE) -C type clean + $(MAKE) -C iroha clean src_only_full : $(MAKE) -C haribote src_only @@ -154,8 +158,9 @@ src_only_full : $(MAKE) -C sosu src_only $(MAKE) -C sosu2 src_only $(MAKE) -C sosu3 src_only - $(MAKE) -C typeipl src_only + $(MAKE) -C typeipl src_only $(MAKE) -C type src_only + $(MAKE) -C iroha src_only -$(DEL) haribote.img refresh : diff --git a/28_day/haribote/bootpack.c b/28_day/haribote/bootpack.c index d4f821a..92754c6 100644 --- a/28_day/haribote/bootpack.c +++ b/28_day/haribote/bootpack.c @@ -47,6 +47,10 @@ void HariMain(void) int key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; int j, x, y, mmx = -1, mmy = -1, mmx2 = 0; struct SHEET *sht = 0, *key_win, *sht2; + int *fat; + unsigned char *nihongo; + struct FILEINFO *finfo; + extern char hankaku[4096]; init_gdtidt(); init_pic(); @@ -71,6 +75,7 @@ void HariMain(void) fifo.task = task_a; task_run(task_a, 1, 2); *((int *) 0x0fe4) = (int) shtctl; + task_a->langmode = 0; /* sht_back */ sht_back = sheet_alloc(shtctl); @@ -96,10 +101,28 @@ void HariMain(void) sheet_updown(sht_mouse, 2); keywin_on(key_win); - /*为了避免和键盘当前状态冲突,在一开始先进行设置*/ + /* 为了避免和键盘当前状态冲突,在一开始先进行设置 */ fifo32_put(&keycmd, KEYCMD_LED); fifo32_put(&keycmd, key_leds); + /* 载入nihongo.fnt */ + nihongo = (unsigned char *) memman_alloc_4k(memman, 16 * 256 + 32 * 94 * 47); + fat = (int *) memman_alloc_4k(memman, 4 * 2880); + file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); + finfo = file_search("nihongo.fnt", (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + if (finfo != 0) { + file_loadfile(finfo->clustno, finfo->size, nihongo, fat, (char *) (ADR_DISKIMG + 0x003e00)); + } else { + for (i = 0; i < 16 * 256; i++) { + nihongo[i] = hankaku[i]; /* 没有字库,半角部分直接复制英文字库 */ + } + for (i = 16 * 256; i < 16 * 256 + 32 * 94 * 47; i++) { + nihongo[i] = 0xff; /* 没有字库,全角部分以0xff填充 */ + } + } + *((int *) 0x0fe8) = (int) nihongo; + memman_free_4k(memman, (int) fat, 4 * 2880); + for (;;) { if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0) { /* 如果存在向键盘控制器发送的数据,则发送它 */ diff --git a/28_day/haribote/bootpack.h b/28_day/haribote/bootpack.h index 56c12b8..3247663 100644 --- a/28_day/haribote/bootpack.h +++ b/28_day/haribote/bootpack.h @@ -217,6 +217,7 @@ struct TASK { struct FILEHANDLE *fhandle; int *fat; char *cmdline; + char langmode; }; struct TASKLEVEL { int running; /*正在运行的任务数量*/ @@ -268,6 +269,7 @@ void cmd_dir(struct CONSOLE *cons); void cmd_exit(struct CONSOLE *cons, int *fat); void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal); void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal); +void cmd_langmode(struct CONSOLE *cons, char *cmdline); int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline); int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax); int *inthandler0d(int *esp); diff --git a/28_day/haribote/console.c b/28_day/haribote/console.c index 3d0c70b..7d6b750 100644 --- a/28_day/haribote/console.c +++ b/28_day/haribote/console.c @@ -12,6 +12,7 @@ void console_task(struct SHEET *sheet, int memtotal) struct FILEHANDLE fhandle[8]; struct CONSOLE cons; char cmdline[30]; + unsigned char *nihongo = (char *) *((int *) 0x0fe8); cons.sht = sheet; cons.cur_x = 8; @@ -31,6 +32,11 @@ void console_task(struct SHEET *sheet, int memtotal) } task->fhandle = fhandle; task->fat = fat; + if (nihongo[4096] != 0xff) { /* 是否载入了字库?*/ + task->langmode = 1; + } else { + task->langmode = 0; + } /*显示提示符*/ cons_putchar(&cons, '>', 1); @@ -205,7 +211,9 @@ void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) cmd_start(cons, cmdline, memtotal); } else if (strncmp(cmdline, "ncst ", 5) == 0) { cmd_ncst(cons, cmdline, memtotal); - } else if (cmdline[0] != 0) { + } else if (strncmp(cmdline, "langmode ", 9) == 0) { + cmd_langmode(cons, cmdline); + }else if (cmdline[0] != 0) { if (cmd_app(cons, fat, cmdline) == 0) { /*不是命令,不是应用程序,也不是空行*/ cons_putstr0(cons, "Bad command.\n\n"); @@ -317,6 +325,19 @@ void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal) return; } +void cmd_langmode(struct CONSOLE *cons, char *cmdline) +{ + struct TASK *task = task_now(); + unsigned char mode = cmdline[9] - '0'; + if (mode <= 1) { + task->langmode = mode; + } else { + cons_putstr0(cons, "mode number error.\n"); + } + cons_newline(cons); + return; +} + int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) { struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; diff --git a/28_day/haribote/graphic.c b/28_day/haribote/graphic.c index 4bd6979..0df664b 100644 --- a/28_day/haribote/graphic.c +++ b/28_day/haribote/graphic.c @@ -108,9 +108,19 @@ void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s { extern char hankaku[4096]; /* C语言中,字符串都是以0x00结尾 */ - for (; *s != 0x00; s++) { - putfont8(vram, xsize, x, y, c, hankaku + *s * 16); - x += 8; + struct TASK *task = task_now(); + char *nihongo = (char *) *((int *) 0x0fe8); + if (task->langmode == 0) { + for (; *s != 0x00; s++) { + putfont8(vram, xsize, x, y, c, hankaku + *s * 16); + x += 8; + } + } + if (task->langmode == 1) { + for (; *s != 0x00; s++) { + putfont8(vram, xsize, x, y, c, nihongo + *s * 16); + x += 8; + } } return; } diff --git a/28_day/iroha/!cons_9x.bat b/28_day/iroha/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/iroha/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/iroha/!cons_nt.bat b/28_day/iroha/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/iroha/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/iroha/Makefile b/28_day/iroha/Makefile new file mode 100644 index 0000000..df134ad --- /dev/null +++ b/28_day/iroha/Makefile @@ -0,0 +1,5 @@ +APP = iroha +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/28_day/iroha/iroha.c b/28_day/iroha/iroha.c new file mode 100644 index 0000000..3ed1dd8 --- /dev/null +++ b/28_day/iroha/iroha.c @@ -0,0 +1,9 @@ +#include "apilib.h" + +void HariMain(void) +{ + static char s[9] = { 0xb2, 0xdb, 0xca, 0xc6, 0xce, 0xcd, 0xc4, 0x0a, 0x00 }; + /*半角片假名イロハニホヘト的字符编码+换行+0 */ + api_putstr0(s); + api_end(); +} diff --git a/28_day/iroha/make.bat b/28_day/iroha/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/iroha/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/nihongo/jpn16v00.bin b/28_day/nihongo/jpn16v00.bin new file mode 100644 index 0000000000000000000000000000000000000000..135f07ce88e6ddefe60f5b6768ac36b52ac3fe76 GIT binary patch literal 311296 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 Uf>;Y0Qnog1f# zT`~I}@jb;%gy>zVzmdh`#$V!u-}mo+U`#lb@L&(r2Ldx#L9HQ!_(r_1U*QqZBg-Gh zxkCzjsTSm?D>DKYNP9cwa0+IoCeUa`QScqvA9#_wbBV*8byJDG}0{l zPpupe45abPX(TfW$IC;ZF(?rloiL$Osf%@%G?bJ=gnNuk_@~ z<&y@_0H`9&Af%$NM9&p}XabzcZ%94>zc8?3`o#74gHr%lKrf4T-@Es&hY5gc(9es- z+5MX@X8wmuZyFnwkMGkERKXuRLu~fK+VC~}Uy`qyjY&Wy-TK5YSDgS|MZTt_3fci3 z*4u=AhWTG3O2|dQLGoeCb^W;29?r%a#k@!`pUd;OMX1gv_ z>lVKS`5o)bOrWZP5`!V}6>$W6`^c}}*C!{x4*96W2a#uPW*jT}?>fpu+v3EJ$2-2l zL$M#v&0WI4u=<&2_%U}$@!)UC6NwCiC(am<={;g0MzioWH4FsV-ywq{QAGqKT zUJ!i5Q`s`9rMz8yWUPeE|On;l)evP2@9k(87Z5$3aUI=HYy(hjzZ6xZ>ht$38zX zI%?>bVE!^&!FL+?2X@GXwdDzYU?=$v;5GzG3|7Oyf9@5w5vPrPUG-b8yB34~wieXi zwot5PLz~5yy5}=|_k5e*w)Ryfej$JH+<|O^LVzD(!jizAb@(X0+=2oLchDVRKu3qt zXh3Z0Gzvy?_ouAD1M91}qoqO}2afzV%Fa1LGQh+Uu{Fsv1aLU~*XK~*K*PpYp7puR zry5^$`+K^Fq0dL)0N&&z5+^Pxq=n5}~*VRp1!>g`oqBU z+K9IjtgaiLM`k@7QZ%l69ul&hKWXXgJf+WA?7L(f(yB?{;5_h&9 zVt#NR|H2lyXz5*&keHzFLs#$;fFO!*WC0<6LZUSE+4YNuEz9ThOEMRM)cBB(9En1~ zP=3%-=9=&92k+^6-GUF1 zCMVlF2y^Q|zpTgKY5z(2zjhU}@=u`jZcy~XO+kEimC)Cf>+cORgN)#l_x>>O?N>@@ z1`YcXbEt^^!C`DZa9uLQ;r#jr{}=w6cr_;Tp7BquY_Pa>Js$zh`X~j&QMQ z%Z#<~hvDcZJ%6S+G0$h6|4RIw{J{470Vg60KGQ#bK3Y@7vCQk}2kyEnAtb__>UF8u_X5o_C5Kh{Ee;6rELl~4&tZC8yovsi26Eu%Re0p6}Kgt)~+E5 z3;qavK%L{dUcW&9m|mMQ1TpV|uHMoJyd5lEN+0^uE+2S?x6{O;6d%XL(9q(>qWBJE zWfA`k=*ZFJ__-{a{$v^Vm zISA!>`BD=E(jkEKSL7o__*j4s@R2W>?uC7rm+#SS8oMG8lH{L96F&J3+n$W|_6(P! zYrM5rPEFKV-+|J3^B*#)b%@2_2a`%M4u>H;-N1wYPA8`KO_%mfn;7Dm(ekIoACDLB z`tc#^hq$ogY&RCTY_{}S)=#SwU=R2cjSgmddtst@=`+Q%y%Dp3bFiCzH!Jra{pTNl_%8V8`mUipvDlGV zZ*PaaSicYS!(_xE!<$#bA>rV(%eKQH zGA?B^D}Tv|EHqL8gz)kAO8zQ*zkWq9E^`-!)R9~J?K_3-miz&k?#L~h5!Tt2%r zM}%|drPC^)^hZ1nVk{9Z4t|EhKqvo#xzJqv5Wq9GGl7e4qn|6A{YJ8b_x;n~$IgcQ zAo1J1NnnA)I^y|wAFaJRJ-}8x&_Vo00Wx9%cI~iL;zZHauvB~<^ed}(aM=1h+ctnU^*Ke`A1mc0z zXU4PSPg`&qd*oxEg8U>}2vJq^{m@;=1C$rYylT7uYJBVK+@JVL)-I<6kMY%>_gZvN z$*ZrP%Dg)NMdW3S%6+1)Y8BR3Q8kbkk(esW!+*(dc_41~GWq`@ibO|{05j@~zJ{AS zrr25et}%#&*nPx13-XKhOVELG7#l-q!TNn1A-y4^9sZXr$%K8q~IFf)Fkm%oy0Y(aj=vSjP>fg;INb*z5WIyRC z`UdwG{*Y`v{>7t!m%$3ypUrN)^HGK_)M1JoL#FsZcvh0Dc~>kx%Hjiz6r9QwO@4Ix z6VEsMi-`~7|NNr-c>pq!f_xym8=zIm9s4yr`f6Z5V9+xJDD-{i(@FI24g}*M|H4nU zKPUfIVswnxLlX-BEpWR)yG$>+`h^Dnm5wiT9$35n0D#~PoX%#?Kkdz6V5;r@0r;^l zzO9g=E+hwu3DP}?H=qZ3h&;15E&F_A$m9#ePG1jj{lI->RTKV!+lx`-DHJl9}4*wy6qpJU?l$C|G8 zos$K|>df^{+^6ipik8$Zwh(9iVWcMxNZ{8qv!3J@&r_(6}8RI|8_A%+lU@)+zwvRxi zXl#3L?=8_8)SnI8u%BSRLHiFvz>p76%i8l}XfU`ulQ*+}k|Tnq>)DrV5MSy|LLY^m zxsq28-+7k&YWSz}5A+V~|5X;iEac^p&&&Va98Kkz893&w1Ek0ik_&b^O*O?o$B zU88upI#A!(kNHJK&|)Nwz5EjTq59kU9w7=yT2>qVOHio#3DT5WezHCz_)vnnI z0YI*$V#(@vGJX%rAj!|(L|sb1xoq+y-;tk@PjZ9ApZ4~CV&wjQ`Io+P8S`=biCT31 zAK_0yD93=E*mRKJu-~%0kcI2?xqbbH_UX3vjhhdp+OR`F|HCJ0uf@*hZatIxUio*y z?|cKlqseqZ*UuDBaIg58T#5LIMErs2F(}VXJ0HSD(B`@Nh&I2Z=7+y2lS%o5Wk9Sw zT?Bn1xj4yFs!;GZeLy`R~xx!UNHA;{b_|1yi}pMpW;o3;Q)dF)Bi_#(V# zsa*1xGAB0uJ@aduo}74S8Z&kKO;glY8MXB-EzH*!-g)l-lzdkSHRQYO9_@c9gvrOf z@!$0~O^5oMiBy&Z@rlOxm#;^#Pfk;y|E7a7&xk(MLqo&EWAFcbY$e4|=7fANX#hr|fez1uLaCh-fe#O4izx!i>{s>u8eF?h>KOFsQeFE2BYg21qlSh0D zhU2^YTAx07;f1HGj($Wa(UFL6JIwvP6qW~BClbg1U{u#5z-(*XMft?*`u#OA+0}vk z2tA)Q2Xh!J0c5S%TYFJoVrm;XcX7sw|(pQk{b zn4%`dBcMmZ4^~Q16mjr-UXej_wfS@BT>O^evkE@;^;nSKu}CN6Qw9v(pH*%uV1L)D z_{2Bxd`mio|GNEYLMR{!48oE&{(pgeC4js-cT$qB)Q64nq#_6sn-4G;i;kfd1l5f) zY5#(T$3ZInEF;r9SVpl4$;gMbf+-?1FZUzKY%NSc7 zSVPz3rAf^8>zc?!L|IZ%F{HSC2jI@Y7s)>%3$d z`40G2=(KX&mA@eLGWmwzB!4nEmLKaVELXu)jKAdzOB7 zlKKdv>_6CzehA(vu~Dgw1sqkbf0rZ(*Dw6^DNtVLgm~*;Lw5FUpA&n>zS)lbt3ZXo zHQ0B;*IMu&0RW0^lKf^H7*}2#hb*1OqTwB`k&v?Hi_oL?@V=>eybPSB3< z2jdO?atJQUOZkjlP2ibA)L}o>MgQv73qbLu?4>Qtr_Jhb;lY1Y@&U^mVeL&zlK&n8 zJTWQt)xrZ;s~=VG%o%Nf)*t^#^c#htCu6FQ5dVr-7_EK(q9pW1KYPor*YV%-+^-bx zKFHIPnJ)Y(m#^6dxVC$@+3z_HG3c^xw``*Njp zeuaHo%*R-+k#IR=WHTnhJB1UN5=sWQVkkoRl zqa(-qFn`U?2B{y|Cri1uc<*pDrGD}Y_~!@4=coPrD5*Jz+cs~&K%(c@S3aMBmaW-6 zq?hoOE#2!uGeU{U$?lJR@|pJ)KjNjDwoo#nBp z&wFcZ{OyVHw-d+Tx*dMKB7dky_RVGd!i1Pp{8if*ZzBBiAP#P6h+g%VJ-_Jv(RM1B zx+Eg{x6|MD#dU|*#SoyZ{~w3{DR*__<;c4!voGX_Zno)>AkO_?8*gpzviM8oAF-&7 z@O!8L08vGpv-XxqiWeQewWB$@ZgVn~>CUQt_p6bUwaRlXx&M^Qoq70MU{uP%7-%H? z7h{;0iQWt9ms|Z zdP6-E8vMsK>6h^~>hmL~nSTe<3oHE&rhyq^W1k)9lZ@mG8zucszYd^fr;e z07cvK1miOJ<@lOVXw#!d4StP6YSzB*`i(nEdH7~k{G+waM{m+8LblgLcbsq+b%JwNhyn^tn)%45FaCt5!!7yFb$|1=##&|KHgf^Yamar>Gy}UH6}$Uzh473$X`VyCsqso4r3Z*GdaWxeV>j&Atv<>l2(6EQtJx&(fA{)Cm7He0UgzMLAuc2R~Zc8 zBNJ}d4DlcLF+Pq>(diP$7G6A8WqnP$MZg8bCMS_UNGB{7$L}qT43AD}KG*xH|FYLx z{XG`X@JV9!4gCf2=lsynpTn=Z|C~%1_!C4w5I^%l{O;v=TyG>H=~qVCr3LKpEnmX| zSE@@3*Peg2)cc?d>&NB@)h4_oM3xyjvvb3!_amZ=aQ1L z1Nw#FX%;}Lh+F|)EVSmJyWISLC96GO9DnM^mfvCV&0{Jd9mMA?-+#~F+5N>JoEF5x zxWDX=%R4OnhSY~$pLp;AexsgyJpQxOMahW&7=uaTpIe!~yJ^3N>1nyaS{(nu_>1?t ztEj&LKdfgi$b$N~jz0m8ZA5%ZKT|)k@TEn;f$@)|;s-1~w4=}U$CW_CH)46&9s-b1 z@Y>tA$$zE=^eO)Y`d(!s{5>eX+GK2yiB{*{{H_wS8c3%4ZS6NN7jVaP^T3a+QmuX0 z>+4kjShf74bz!vr zd=mcR1PBcOsFc}`FPQ+L`X0nz!Jvu1vi$7xrOAJpeDKmc6Qz4c#vg?}RU+nkfB{#s zoemwnB@tc|-V6P!I{FBf(NiU1~sUKVp?=k?dc&rcX;VS+KnYin=KCXVm z0E#a0NP{1MFADU79+rENk1Gc$<#|*ltkfVn5FdOB%onsFw4BWoi`4dnXNix;dTt8% z2d~!+AXb-F)Za4tCK8@!xX2eIH{z=JaZEp=Z^}PiK{2>HgmL9@tKa4nZpa*ID55We zJd=_1_V$>4M4BHKlu`-krofNY_e-FEGC*0_y#8~AYBYXo=v%)svW|Mxk?Z~6NV4ti z-Rk>YjNjMb?OizL=5H$yzb>K;sNh)y1+mK#GeJ!U+kDuo;QvCv%0CxFa=VK@>|f9WmRB;K8X5Oq_&iA_`sT|b z*N1%X4@KiUALRLrfjAs1>~ONVF%CUbyU)~6@b)rpt53)R7P7tQci6{x`T5?R>8@Lc zKJQiQJ`~uik6gpbeL+J8j!0c)3G$xuJ>B2L*MygiEo9lnJD}hdHX3G z6nB!p%F%&&6nw;dNlH%}d&57WpVT%dtxI|r`=jqCpRIzAs*m~!{I9^6#lJ(Api53g z&R|;7^Qci;&Nj=2L7f z)@v=1;D&u#4d*i^=yhDc1zno${P|H=Kj*srQ1weypT-pikQ^cT?SuW`+jGzT_)k#+ zUU=c`k7~dVtFQ3(N^1*`kpFZb`0D6WRA>XJtaa zT03@SR`~w`|0R>syxb4z4>$B%>g!P63`7DVwm<*qp6q z=noAi{bSJf9~sC4a^hBBszCfb{t1%~B!8TPfLc2Ry~6&orMs-?<3@bC_EZ+7>A2WW zpNC_S!y^Vr4etHeZ|}Q_{FCI{OfNRMOUqJFJSFoO{3=7)bVbvcf$iL0Srq(`~d>Jb%??M?5$#oxh^h&l9u z+R~Xbm1wy@k=jzRAo*YCE1_pNdd1aCVFeEt3RtMI@5nzuxeh**NMqkAm;sO6MAGZz zpGj|wH4mjX;>X<>PiIP=_p{iK5^ry<#ZO;LGeB;OfLSP*df_xs?jH{OzRtalgu$P* z^UwG85~sR%f&U{|&LQiW2lqydW|V^_4`umGSSU z4?%cf8^M>wx5V0#yGK!Otm%3&2*0jxsN8%qv7t}GCH;!u!Rq%LNH7|{v%f}T*l!=A z%Uz#4lU*7em5HkMJ$L>h=hN+eg!F4}f&WU?sO!lYoI22tzd@^u2=gU@P{D7%)&mBb zts`RfK9~ijKFGD=wanZ1y(OIRa}NXo;Rgw78xxzqs{QHnY=3I?$hGI({_xKyH^g_|LH()~`)l@F+h6|q z6!m4muSw${$QGC&=EVX{e@DJgwj$!EVySc`1iX2Reqk|tIqG4;;4d{+)x;a=w{R8V zJ=g_inf?q}tPD*Ke~#DiUd-n*w$RYGG8yon`Uv%BS#8i`gC zPjrIVHWVP9Z)9Ck0uu6;75b~-6Z*Y;eIUOPKN=dq14R9??yUnW;lt%e|I48O1Mzr}3b*~ov*}{K*{@C2} z3onU&#gn^QBa}#NLqIaa74(-jJ6kNVf75Wd0Y5z;h7tV)>j&v8)aFN3$NfM29Qwa5 zQtEDB^^uQol3=cE@$<;X?@W}-Z?5ltBe4Iw{Mw!jd`|KO*47_2oY$C)^!QCKOlWFiHiuBKR>+HLIV4eK=rX_({Y%sK7+|5<8_-{E;t3 zS{k+lne4qmTwuy;^l#!z-26;Kv-wG| zR`RF5X5rtG{|}RUXa=VB{kng9|C>?xd1>O;3t`Du`ApYfChcd6#Zm|N_k#Ew-_Z}j z_lo-E*T*;G#y3c4L*Cr)y|+MqulElYHU8`Nv)-KSE6h;>+I9Fb{y>qtRCb%QkBRU~ zh~XvvF8w{Kqp+E_)+h9Qc9bm$;#0gl!wk!~ z!AdEBXc3@T4v_~+)P;KEa3|=$tPx%SRDge#FX&_Er06P22lic%hrh<{7+ypC&Fi+- zEOOg~2jQ>R3_5JXYAYhm{O!?~4Gosez6y0q!TKsP6bgSC-(`NY@NBa$8vxBKS80PMG2m|blGX?J;jj35E5ILRfAFeAQ`!4Fa@f}wFrdiUu1N3G2onIuupl?za>DBA&WAP({d=L7wq*oFlp`(2u)PKpYU?HWz z(U(l3VSL-VyWi*QYY*|yudM-|Qa-20hE~H}mFon9V)Le|{NmQ9Gqd7+5#%kgZdq;t zaqS{4k6+koZYm54n81OwTFxYeK?#31nt6xaGyMRdCoX^-e-~dCjd4B($6Ig)i1mwp z0=3G|pg;`qOMq_M?g^qyHv$0g2lxxjgIz>Hn`@$<_}SYn{)3%X{;RqOQE+++2#Z_D zLw`_w5%eAQQ=6~SOG~GLM?HYZ0Q-RSW2bk8_$9jKBK+4=S_@6VHOP-#R!`F)*+-AE z|6o^zxYi^opr&6i2AANd&k($R9<3OJw${J`&Ss6{`*TNuo`o<@JlBU%I#oph+arNaDE9 ztg-6A9^fE|In4S%y+}{xfN@q`_A`;~AU&0R0^u0~=6(Cc{4d;><3XIEm43DdSb#g1 zO80j#E*R9`lqabGhtYQDzhqbHkq9BCqj+k`{|QY0s|jB1v>h_d%7~-c-(5eZ68NC;AL~cU z<@Raew@j-LVBV|n!|+&^58EF83D3Kb()gI(_579_=f|L}JRbQc{F>nN2*9(UW&X?Z zxbh%ln!nZ;1>Rgh{)>h0LhtG4d>N&ux3Nq*A9soD4vTRTe(L=A0`?;qoyC{Bb+J9P zp#UdM>KB_%V?P4#Ov7d6to|AGG56mV=L8$5T)H6puC(LG z(yEA^??wD;6a7upN8YITA^PAQ*T?7BHdA9MtpPl;jo^M!^SqGQ8xmVeh=zY5(7rr{ z*;g55lb}QTHz}IJ-xcel`pvRGYXd$uImYJ_j2{XJXfAQA$5Yg|AU*2APeWmL-TB}| z`zDhg-2s>JiT;V-!+)?Gzv|A$1ZQvOKav1Pp$5Mf=r7jP)HmKlBUN zO+FNE-u$JAtzY!A!h8D9nW6whGf=bs8;~l#U&ft=k)R*89>~Uu<05{G@uNYKT{Mq= zx98_#`wGq?KAmTlKFNC3L&L*0_5uR4NpKVZAwef&n7N$-j#I1fv=(SP`0P+@43&8(Ywie3mJ#QGry_ z%S2zuU#!+oUpjsI(%hv|7Jb&~my%yJQ4h(iv{XVnK+34={2*rH)(1Ef{sL8QeOM#; z=LWWAnZB(;6ZNhH--|T?*oR;0MyLoXfiWH#nNX~rSIU%g)PWe|Cr1gtz2p$(Z)vRH7}3 zwk=cApR9b^Ta5UnmlRK8#Dfv)Y!0={aXp=V28JXbAaqa~!kH%^GgXLTYtv=d4+4s*~=jbQAOBG1v#9}{S z`}3FQmuii_MHzU-J2U&+Tid1>U*+iJBq8Z{OfIagLZGxktN|Gm#=lH#(A=r+rVs-y zo$Aj;6Z_3R5e}b1lu$!Jnf<2d2LVP9Ufo0M!vOhm>J{t5{*cGFV3ibG`U$! zQ5J}Ni1{u1pF)4q1AYe1TV`4DGD8wRBz{z3A9ckC5dXR{zP)@?NA4a1qaVZnf@ANs zD5s0K^ABWSyPI-}5u&$ydiH96mAi=I_O~7Jw;&FC2rJlwYJ`!o8~R6Xw#rlTvC`bT z=s&BI>B{hLf6lb*bUM%cNgaf~?Y@Q2e@*dSIvMUDJL~+vd;m5$8`)AVWmJC}o}Zlf z)Wq0m92dnVli$V{GNl*1LSLjs{^xaw!K^V%P&**_MZ0rHB*f)^pf)%MAXorbEb%Dg zFPL!YBuwCZNX-8ru<7dSdl!5fvFjE*E&n=%#l(Al3sq#zYpTS5a_0T@Cr2eA zWf2TA{W^d@(}Ge{q8s-A!o3F#zufd1^@Bd}{0`YKKN$Zi`7W%p6Av9adlnRA|GJVo z04DAZn1G(S)hBL2Kc}(g@_T5xwjSijeMgSzK_%feKz@Hg?u8@1Yac=wLh)P zrN8kuA=>C36Szix))acS=k+(CpJ4jPW_NrA`!KqT8Bmvk`mMl^phuu%`{VnW?;{z% z#2Jq-H_1C&@NArd6w`KVlI_hGn;#eZMrc+0Xt2SC#ERYA^0SkB0p zTqqyAGOq}NId?t>8%*qh(gP-rtoB0QEWF(;2L&ge0Avtu$ zW!fIo5K!aL|Ac z02#&=gQ662P?Ybq}t@&uHHGNG;K_^oixplUfFHsM>J2l1@9}|=M@$OK>S0o#RJ_3pdthO<@;B2 zB=&C;0MI-mFWVITwN3$aZ73 zHtt2vM^fwmhugC=r0CKwiGBmeebhH;D0qyI5y4-ae-DiGB6A|p z>=7c8osU2T0gRWh7u8RZej)#oSJwfCI)BgPf0Z^Ne~o*2to$fsZTWm(HWI=#E_eapb%9jPFG|_iuS@@RZ`8>kA`hpT;aUD%z(8{8sCXZ!q}svhC|5 zY?ONw|2aEL^*n2UhvavQV6p`L!}{aK>t(tj`=uj2PKAHu1O>Z>5V9*M@JF2=CG&}?7ZN0ipG>I!z-=l&!(NgOk})H6X)gL^|9RvyGV`v-rwuV4 zlP=s3_&4fNw#3=BXi+rPFMEy3EEXVgmB~PU6x&TyDAgPK?;E0@=zi$&EJ3d|{!(*-HU%o%l+fI&3Uir1+KTl!Y zq)62w0iGVLISB;DHyz>|^^-A|WDOuYhN5A9wO4%&qX#ksp_S zJjQ&1kL3C!`Yj^NF2-LE)yF3Y!tx+cisuk-+tMrMM)QD~9 z{t!@l4*#pMXAlY67$NsB*MphqqnU2ScgL3$0WdlV!ZM8nxt~TwRz)#MVt{e$ZG!uBj>m#~SwsXxc_UGcop{%+K)z z^7jiD{rX(;(b}%_&{F*KZ8#_6Z3aKdUC4&--amdN^W%~8rJsz9{~V=P4nnwyUYTur zROLJXZtmsT5cenk_>SFu4~**e8#o^U^2@usM~j)e}VlZoJab|QC*=R`4!=8$*W@KGfN-z zr6|>!7j&$H@l|RjL#o6V^cM1?&Pwd#rEnhp=vU^{U5{=Ze&J&6S@09l5XHrmLxCWv zl?DIgv+@AUU1L0Zyd&5B|Ky+jlGoWf$|*14AIz9(&paX^j;Dy<0=SlPB|CwP5rE&$ zzxpK$7XyCC7dev6J~ZE%x!A7yA=?bqTWuM}XW+F~s#o zmlwTiDJ=V!?ycLWLR3beAN!qi|9I|vHmQxOpub#S1Km|4boz;j2;86Q4q*%ktNVld zW5Hnhrr*vWc1AxEMR}m9{z0L_*j4_{xo=*!4Y=5rTpHuvGy&8Y; z)8mK!c63zyO+#1pyM}#83BJ-xWCW6Zh=+=GA%5%muD(7SX!UJO{$+8rwysq)ej4Cs z4FIX|06c5sEyBMk_Jc{9tpmgwBI`_?)^3{X#Osf4*v8Z(FkWo|c=4v09_+ z^U>OCue{Rp3hhte*9>Y#x*PT1_*L;51Q<~J%C$Q5f)AJiLI0Yl;FCsmgwovXAO2iM z8-^8K6|SI30iHB|%!SF{umiwu(63_NS`#HXvV;JteP4S6{FPr|;IUTjApCRs-FM>I z`+g+_E^ynh9n1bFLx6BYelTB>`mA5|2aa7<+_wWG-~;!*4i9mNz@DI={GckX4tx<3B57x!rxUu5sZ!CG!oZV#Ct{1hi3VzD_Ix(*Dw3~-cU1Wwuu)OBvLQs@Bo;J^tQ_RO6|)fBd{6~I z_5#m@jpgFmJAWS3w`5#OaZ4T4_>d1wcv&$%?@8pl!{vL*!-u*3hx$Y5Lg zf53mBlV~3C{1nv~e0}-Q=i1!T(`OgX&gu*Kr4rBoR+c_iKzqcgB};#@K%WGeTAlG= zU+zP{?RzMp%h|sImQg^sjuS=t^I`n1ci!?_Jw3g5a=z}32rZ!X)rlOJ*Dk4WG07Z*czMS9(rlMhfZ;BaPN z6905t#Q8$N&+2}{uM~o%F${_p*Jq2eAqxw+zieNHbka6R=ldWZ5}1X>w^ba5$C&{I z*Hm^}snooM^^yE4`Q(rL%?fU_&jZ$xRh?7dSH?&9dC}+Iwb&{kPVxDBng%TX8TwFr z{ui-axgPyR?=Q05{~dbd+37tJKBieIkK_hfPCYb`vk#89GOlP!b{Sh|7TQO+8lA@` zqjly}Vn5f@|#pt~0CE3DNXTEl#J^uHYa z9(#D1a|De={Qz=PGA`_J(`fIrjt0DqSN!}`q5)xLYKs;2WLEWSY{knEQ=8vi1^ z_ds^{#KgX5fR~`YS6-aP$!CVS^=iTFj}Yxd1r4#g`^oi5s3IFj1;}~rpT#F@emfio z020Mt$&dHqho3bj%QRDs)ai)f_rN(2Or_fpP?Vp!d_Jtoxf95^EO>B4;feV=tJLfb zZHd)8btEJ=>2=6QUdxd>=WJLBpbZ?6Pay-kQzx?u_BOg%Ka*EqJ2eth7 zeabyzm5m0_Q7GLFfa((_|3Vk95Se9k8v8m@GvVlZSE#aPQ7Br`ET`zv6knFuK!F?4 zciK+!Q;v1{i|n!h0X*az$X(F^OGxRW4?YRf$ilfZCSNK)%uXmKeM9sn!j0#$?dO}f z9GIJnD8AC-cc?Ceq67STXnlTQpN!zY2ES*n%V#D(nuuX|%v!8iAIl%-{}bcK7m~Xm z7A7xh&4Hcf*4@}YssBxE+Wd=pfRj(5KS#*EApat7`9a0miR^NZfC7f)p}f3Ito zWm~NvaJL-b1{o*efc(xT<#&=`NB)oYN7k!pZ=$!y6a9%&oM?EM3YoDrcsTfTXvp`s zVgpOR^iqo3i}P1p(K6{%z-~5oItvJLyp+%9RlhdyAG!Qt{8P62lGC*Q%AdT;Q62^; z2&19=u>$>qKbn2xb_K^C$bGINAS=I;PT~V~euO?}_Eozc;f5O!e;` zzr_GJ^e99#{SwZRcUHdi;1u~49N*x=9OS7|~57{pR2e@DPcK446+0c4M#KMVRQJr&#(pLK01objPP)-Lcb z!3aNeYsn9Xs{%m~oG-zj;|~q?;PF2xPfOLH{-(mG_H<{z(18HbRe--!nx1{G$NNS8 zkT;colDo(GPtcFR>`)BZ1}`-02mFMdr0%et@b&0wM!>K%xVle)%`V`x^$7wzb->8j zD7V{)dyakuhc)sqmgDQtQHUQ|dzoh|_$$AI zf3Y*|*X?{~;!`54*0vI3eK-9~0QQ~iBz+$Fj_C7c1l9gCO%T)}xAvd=Z*0Gv^n{JF zbVA>8yA?lOeArv^xefNQd@OMPjsUc8`u@Ch<9nU01)wTwOK+?HnV<_2(dlZ1`fzRrVsF0yibAr0O>%y z$HEz$e~Nf?h3ZrmzGn6xt)7M<0ayBsR!_rl`Y*fz;*d_~Bd)$ISxP2ZQl9>d>X!>k zdxe_P0Q`c-!;9l1BYdZUFLWn1?4Hox;oeGkh~A3NYr7EbdjnI5^mEzP@$P}28RQ=h zr#)#WgI7z6A7a&&U>n!@h{nHsC0Lpm1L<5;epYB-cTWsG4*jC+NuT@o1dv$^g`_qk zp~GUOMq~d3{Rn_K)^s_(1qRcndTiKdl6Q)LD*h7xhE9XcHT-8c?w>zUnlsN{U#mBT z{6fFWFZ}5C;o%tPZ!M9Yy%Y~Z*vO|DOt!4v{6(UGO%0HJ6Tfu;0^FY=01GBKy&slK2qT;Xwd!!Z_sZlx^y@7 zU&aK_tdJK$yyxMA8o-NFDP4u(Nl*ZQ_|0CqB->dL0h&{HWuHmmSv1Mp&0n?6>lA`0 z1oKCTaOV>Wyue@G*LQ>0Z}`V`zT!r&MfyRe}3)C;FS-xQIVd~!lR)7`)4&bG!44i{A%El9fKoVb^ z#(rn1rR_S5fDF^Dh=$-8okR|tQEJt6N1!SLV`9aB4zEgprikvT&7<*ft& zrSB@3T=8yH5L&CPlK#pEa)@Y(z{Y~(8U0%KqLb!wu7@KH=%(Ql9vrSN*FOtLMHm$HPzaxfhU+bvQ@p3HsqEcL(}EQ97Bl zKjle2j=B6bBIM-XsMfYznUANc#23!1zBZ3N z;t?62&Ba<3Kco1%T=`q>{%^wn^NDDsFxp9Y@kc}e2aykuki`EHlAuS}%9qctp#Gkp zz3;tT?*11CGw+>g8f#kJ(u91E6RFrl{Ji*|L@*P>sLzzy+hP?`arm)*PCfzv z+*|NT`b5c~l+n=OuNUp~DPru<&n&z|@s;CRVRyYe`|b@&uzShmuHKR%IQ+A6v~gsT zVz z{S|jUTRQz-I{iNTBiw|0tG+6;06(EG+8Os2{E#1#ooPV|KnTD~vgNWW*I}SxY6un- zhllbVQgnjgXJLUdHS_c3Y<6J*T;hB$pQAIwc<%{Rr@yA~Wyyw1m`IP&e}n!3{!4}M zW+GyV$hV$OE_1C|fZrp%nuSU|>NcbDVrzi>{Vd)3P> z9B2IzB%v?S*e$&ytiO-wp5ywNHw=WhJSocRh9@%ulKt}V#6KMY<^zrhqkfoW+n|Vk z(bnJ=lsY#1Mx0yJuFjJOpneGr=0Tu92X+mxBeTQ=+GpMn2(x(HdN4HTg=`fWpPS$E z`0U?W;7r#o2SY}!L}3v*hlXaAAKRYHm)UE;OXn8~e~Lv@|I9vNTAT6K&XD|PY7$Uc zOX>(Z`o7Ii`>=sR!IS@P$)m9Bi||0K)aQ);#Wvu;WtBld@W%>x_^Q&a`bf+_nz(cI zrm05#Y+{2L?WHDHN{sjPJh8CV;BD+dOz4gJ zOE=t~ss`&-9~J1Q{A8O@!U0a*s}CRF3g2DVzJBKz;yW+sYbI-l|FR0aj!{3+^fP3z zL1-ZQS@w(%ZL7~^bU+jFOXv@lI8!R4J`@1vB~R8($Km1PTdAy6B76W~QX6w({{zCz``RDpaN_At+WVgCg7DN$ICF;XXUYFU0(`~=Goj&z2a`+2_NC#qFus6$K){}DaSf35mQfqeq|+)=%mUp|+` zMC0Ul<*zI~|NOkLToFWPoF-0w)a=S zKMDf(;03BjJTE-gan75aJ6WxU-cY_7AaQt&S-Hp#Vis5ZbH}foIQedE?$=Bae5O7% zh_&UQhPe~`GTDLP1?D|PKYW1$Y=VC7w^SrCJ{f`4KE2JReOcVxX;J`lZJ+KeG4SB$%nM_5B6}MAxIgCOrzLN;2VH_eMrSs(%Q7 zNq80?jeNMgzM!%A55dt^Lb}nPSU3TOUB_SL2Ml$^y;zGN4Ee~16V`?02UyN?(!Z(S z*4DIsy^(CzGx1g;b$o0Li?r47l?(mPFOG`lMhd(XZiK5B0@GLg5(e1lva327EQ) zZ=@sSH4n&m%p3ThKk-KhFb(+yglCHevIp!5p7IY=o5a0|pTmFEwm!(u-4hOfV138O zhK+tW`G45(AIl4CuZ(b`p|URo^&@3p6aOx#gW|L@-yIbGMP&Qu1*0_lWal)#s{wqc z@Q$S*V9tL8jF#s*FF?Qwf&WPPzcW;zA0OBG7@9NpXAEk{3OCrFB;F{l72u@JfL~Fb z-XL#L@N2#rtPS&lzEPROv@?+a@WWs7ZEyyHfqW3Xrw0;v)8kygv+MEBpJ(E8Mgj2` zKsBP;VkYPphpgYW_$nJE|3Dl1?Z({?wPW9to-*}^)eDvYOaANJrB=iLZR{JdZI3HH zO!$8#ewh-wqc(ry52izV!UGm4fEwDsFCY8!H&vf<57No<`C8Nm(aOv>B1C|XLHZ@1 zI4SQsegyi__4oz=5g2s)tDCs}<$R_*%NH69brK30BC@fd(787boSFLWEqkF)&@YYO zb{P327{A-$zO`O?do=asXoVWboUy|E*Iqdxxwo)bnl}EnBEOab{ZD*o{44r%%AaYy z%-*lG&${~6LHy^V*rzyuj37g2z-9i^`^xuFzl`?q-SC4O=}RV4QE5s!K#;fDU%WE` zZ3BMpf`6}Uf?#VXZffE`US2#7`>fGl;9uUu0;HQz&(#t?**ZiIc&|!rDZcC68>i2> z>Zx20X*TPZS@D!UQndvAnyh$FSB<@O87+%Af01~jP@k4gr@T;SIIkF~WPbG;)kmBq z_L$I*g@w11$=Usie~-5jpoZ?>xt}AVoPL{e`3>JDzXbM0eOsh6j;9KR8S4t^ERnvC z>o;;Vk{BPr!pKnKg zEU2qKd1rMga#i%T*-meh0EBsv7F2%?{GU9O1eU(*{K)`&exC9(7KSJNWXM;E2Ma#Jy>_6He`3L(a+}(#SVLmO_=EC4ZgL>=`jR8K)wu6+X5YcEI z`q;+$CHg-$@c=W``8D;qrpEeQviRzhH^|r@LlcBQfOd;J-#C2|2Y220!$8wC(FX$| z6!~r7|BcuGEBa&h2iX~3_3RJHkt9Ak4Pd+cvrYS1Z^TZfwtRkK^H(2I@t4WTui|M2 z0FX~R@R1;3)VufmH{1WixSnam?@HgSUspgq=x=*62L@#Zk$bk@IpsnA=fO{Fzt4sX z{@@nW|IlxJ7{NJUp30u{NQpnhJ|*~xKU}J?Rf!?;#!%fsnoXvqah;oG>SAp!aq@FVSnwPX8Ez;pAzgzLz8_A>q$Jt_>}4=JKXa4+(@|X5mL9i zyL*nbB(p>6_ol((^2kU@IlPR&C)(4oDY{1K18Y2Fe+#Y#4zJb@BA-A#ECM9;xY)S* zuUPSX&RBvEc_a|QgNY5nyijZ^kj)@^+B_&Ugh9WcoAgQ00`w5kjsE`pa|tNbT5+DG&UA>v(r zLGmT3RmZx{1@0@>-?4UyZ_+QS@?JU#3FLSBrIQb#k4`>1e!R~40d>I(1fLsV|5W;m z`6sH}0Q+ahKUAH6;zs$6Yq)y(2HJlBJoxhS%uh2AXlnS1zoxVVAYcGc41qtO1t1`X zto4_CrX$QNk%|I5=DUoDX1aK1D*7t!@Pa=`Yt2Pa*iA0s;Eays8l@)7Z&f&7L2 zM^>4*e?HpxI@@{y{Fdb7Xupb(2MX4EEv;8`Z<_s%{6^qI>!8M%*+@CZHIb@^^0A?% z>5v)cWj|DXV;G>`0z(&H;LaD~e5@&+uNAWI`o{LLLbvh-l_-IP-eML1swXV0XNkWL z8b%Jpleo|GtrZHsZ}DU7S)x(B1p!qbhqAd=*N+PFPl8Cert9*Di6i0JS=mWEqAL_! zCjuoiTvh7nl7IS+mpY}va)XrJMc=dpgkP(<=m2IY%@-GDqpvY3ITZU?Uox+YfI(=QI8?=G1aU!l$j*4CvgE zb@g+#KTdu|aF!Cr55-=TO25{(XB6Ldx9T%+N}U?}!vNu21nJbCc?KO1wo|EFQ;EpeK^aX1IJ8B;X#W3iY$dM zn)yifk53T)a|f@`9XKEv?^0og|By#*&G?kICZqj*6p%r^3lzN4ENgJ1 zeR)2fA6=23j{U4ShEt6)62;FJDxx3Zmgg}Ty`icvY>*&p2ll=l{_ybK9o#=M$4p%O z)!Y`vKgh%R73h3?qt*w=b2|{9U())x1Vve-IsYu;Y41a%5H|eJ%sdc)DT4(3s6LGo zfH|iX_`!-YDC;!eGHkfuU&KM}_xN3Z%RrE5_|GvPfgRwOed+mVKES^7E|`64?);m7 z^CCq8=AH)s!K+8=`c;ec3Rs~h#vzfrzt_(>VJhwmvLZnpRl0Hw|sh^q08 zjBx&0Y|G~Dk`URyMHKpdPX|cKl+tY(}$*~#o^`gJ<3_Aln*dp?@$zh!U1t1e~EUd!BNKeiT-@ABo|!FZQ`=%<%l zIQ`nC(}UU5r(eZ_h(6B5(Y~DgKzzCI2j~+Fnhgg)oKbzb@lk$@Q||_&k`%>rAcO2n z{8Q!6b~of-(;wzk|IBPujF0%S<@z!~{Fs>t02AYHqAls2y}j9yVZ=ADQhSxHvA52L z;DL;~$>JAHeyW{Vc1X?fhyLK&!UpLtfVvkAlHV`K3)o zLjG6+`Xb{D8d9(dz+anRh{R;xQ$xNsvD_c@t+Bp|#HS{)*W{Nv(P*xR(}Qz64ufA@R4L7If>EwdhXlc2t@y$E11YzZ zoR7JG;l#1qVBS|ne}nZS_|<1~DuH-&mF}Ql=UdAC*YJ-py6gJ8;&YL2`#!OIY!va^ z>A!A$(Sxtv@&l_6V8x@yK_uc6ki5%vS! zD%elzJ|4;S`*AcXPo4UN6Q6=61{H)@-w)28{7eNfS3)Uqx(YIhqRrBI=Hb>?|3gHU z5F`5oYp!WYM(5cSrOIcuLERqVEvgR_UZB1yh*YY!W(){yJ1{`-KF zk0k%f{*HwWA!7;qak!XC>3I82R%ZkJpLqEfL6y^JW2HInawC5V+F*IDKLWl6xcTUTBD2j5WolFDCOLHfG8x9#@N&rSwHfpuwS_VY}G%t{kPp$el&2K zf%>sUD9Gry(2tU&qq=SM4Eju$#YaUs)pUgTgB!00zV3{q9=E}3Jk>ueY>h9j(dO|+ z-UT{PJq&K(;;r%dExvEl0UjI@J4s^KnQLXeO6)P zvuAtwyIej=e;3R$MtHCKpZM_jLh^Mq{3qbs3i;aq3-}AYl7D1BS?BS$#ZPIsao4~f zWQCE4)Nu#|N#4f(KupjLFy7KcKkR&MXFqoPxWzmtkrKJ{}%pDyys;NL0fB0_)qjg82h30n>_Rz)(V^u;M<5#%4DO+ zmooCTN=0Xwk>^(pZXp~!qVw&FZ%BO%lh#i!!HRwtfu+D zV7!%~&kcQ!ZDON%>ly;}LXXou-E8f`zT%kBX&Vb)3?xoY1uJjMrl`#YAg6aBb~fy+cU z_15XHi0*PFDPDk&?rkPyi-8gR%d8FD1^zMod$}%{cBFf{yY_vG=SY8B^k%}lT2{9l68yDq zoNjN!{~U*b1AoL%#mD{{`+tq#JlTWs?`{xzm4G7og!qys(I9;Zz8m=)CctQZJVWMT ze5CR}HtGk<20jJ+1%NSo{*3uQtbQ^6S=B$5{fnbVVQ+;3XN=|&Uw+o&H?97$oxi2{ zO<#K_3Ww;Af1-7$k0r#quKPou3s)^Rsv7tQ(usAUyVJ>t(yS=Z2R;26ujj{>6V0KBdpV{mMsYe%f=)k*y^Kp+inShWg&r+NkBHvggdi!#|DxZBGhd~ zmk2HwgreM~cBuq(ovOq$yOW)o-Ac`!F%Ds8Np@;NxNPmz)=Xl2sTpQ=_QoMhjd7Ij z{r#W!v@FBDr@LiKr_a~>KJWAKf4&~%E&2n&mUL7Q#;3S`t>V?vtz-9(jg5Uz#0~pz zKCwx8PAZ^d>u<i_xd z(qd|W5_s|0#^%waF`fY+M`zNYzHpTgQw(PNV(>j0%2$1KkCNcKs9S`DndX4vI z%NE6kKMlS>;>>9iunIYl`ibx}1gX>n{$GRpDMP0Q#yrw({N*bCwwFqo%F37WrVq44 zTLis{AKByg6t334ARz8`#RrSOcMl~SVeq#M9K5=pl6V$Bd{D(-A3^_z)Aoa3oSQut zEPr!hg*1+2g7Y6@|EAa@oy@S}_sH*{FmZC_y2~EZjQ(!@lakZdjnY2}GFz>W5}n`d zZ^>ZW&-ji}IA=jJDB_PQXgQ-Ch(hs52>saatXwjrc7gx6`Zcm{^7Ky*Jv4jxnms$u z4}VKYH$pYiTl!G|ZJ@kpOQ8R{`LzP|rXMIc2n!mN#F&s5M}6Bg+P|Y|OILbFw%~a* zXnyGxOxrVOav-FvhfR%}dych28-5o5i*E@MOyX<|_cjKn(CsPFvC%TftJsp%bA8C) zr+yRp`;Be8#u#Fs`%f^tCIOLh0rczQr<0;z`2TFt^ozv_shG1>;=hRf+Oxd}7S_|V z|5JqLKpsIYdq(Sw8Sq=~wfF$)gA*UX{qT27o{jQ%xWTUooFl*%dm`p_%*AWl&O%>~ zjEV0^mlLYKl03l!*jS#^SQeht12F%JWpLXx0ZeE{a}j*bzjG$Pefp=Z=5Kshzl-5M zV#rWpoPKt}Z>}w!nNtA@sW{9J3DRQ!(SEp`^B~suC(5*kCq#;sr1(zsVcNq}B4}1} z3SP9oZ%uvKFGTpKR5w1N--ZeTol{kK#iN;FuU=`mygm zG=AV`{orR&2@ddgY2Niuk^6@`fe$w{$LsaOr2kdDfxq~``lG^h*3@_Z=uTu@k}}c!AlT8!TMOG&-l7z`;<`#1(r&iknf8RrzJiYu>vJOhhP=i*5>u}QL+Bj zmc6I!K^P@#v=RQw5IQTg>m>aL$Ul>THG>ta`pyk>jyB^93#Pb1?#aJ5+H@gent$Uj zf)Ny-!r)LGdifmoXR)_K`B9}_QMUQV@!zqgk-qkmA2KGmyz(D!nCg;$1fEb?32W3K z{_09NxPkp#fQm?bdW4@;bb-ZZ7Ws_3{GdEsLduV#H>Dqu;8m&NLv#48w3qA-inr~^ z9V`-MAnBW|7I;PW74e~=x`UNew4p5h2G+#<&VL^*stP`kA8AT%d@PwH05&_!&RWmN z$n&Y}U%C1bvOle|S<>ZiUG)!DC=f0Evqk++S~|Wg7wX47p4qXts`HQfDXPn29d-#>(TmNCJKT2+t2fF$*IRLu@)0>U)Gt9O*!%Do3p{{uGGNCyNfR6YNS10^A zx5}SVf=9%kBK-;aH2zfApSXM-{4o3w=iwvKGaCQq`O4`#J|4AKvi=vf5nh@n@$Ybl zzoEFjbp!P=O#cELv*4XNf9CwVci%V80=WVGgD3dV^C6%7K*}>jZv5H16r5Lxw{k#u zKK}0Cvx@;9xGxic@1cL$3{`__;;&CUXZ*{R--N!k-VL^8Y3bitqu*?<@uaG>Mf6cs z{X9W$Orde^IlgY4SDeiRxdV^=z)!m46Yw_+-*w@2j=z}`%_bQ6 zjoX$ry2)0k>IYGOfR*W%D7pgtA=z~_-F!k{L|=qIP(uLdga1jtC|{?g3kl?dL+~HJ z`o_RtuXkQL5i&;&B)zGYIC-p;xzh1&h8zK+r?w?Jk0)5c>*=KE@FUb$*hd||(!7;5 z4|pO%FS6g=KNY5RnBW|=zIIlZ^4E<)>i$*!6aH!hl=yOMJ08>)_6uD#0&>gD^fLgE zDE?)N-?M+~bgb}|mos^hjr^w@6L~dhO|ZTy_)jb6vgfix%knr4DSw6zb-DcTmdtV+KyYErLbH2#u$e8-Gtg9v7-~Z3ozkkafb#Xue|~Tl`9}I8vKt!OqxwR#g<_5R?W{jD6XbtRCvb0?_+k7a^NHmr^auS` zfwRQtv!6Wc4)GuDu`pT5f91|>&mFh$ZIbdl^?$%W$$R|G`0T%i{b#US^v>i}KLKI2 zy2azjuV{ae&1@f>f)w;kxBbye@INuIh&9>z3oAx@s7@jL_k();n)EO34|^G|5|;%y zRL>vGa|T40>8U0^jQwAZ^3Q|z=7jYZXl`y#lV7{`{$~rfINU+1E$6r%`jpnJ@&wYp zD(9ge{0AEnk0Sl?o-ls0OjnA<72?AVgc`qOV;cWD9NaeWzeLuV$Tp79AB3aa@9n`3 z#lMIzc3j{TD`9o~@h5HmG4XmG`7Ik zWGOlQn*6*z<(D}8jrE6ZRdVw-7kg+_ZjSoDcw-}G)13X|l@(<|&*arvE|J)Cb z?Go~;cisQt8}f*e;-Mcv-*x$h{M#k^uXz!Ts6Pm60tB)-*>O{eM}hx(4BASf!?=&| zU8*B<4&X11u<)&LF8N08zy}#3@iGDWb60Fr<3`blkYJt{{5`ivs~;-~`PCz3)t z>+9n_uAt3W>n*!3LgL$kK>mwZEWUoTD&MI#a%`*TT>z%3fN~MOGgZ;!Lh|e(K0^jH z{7)KEB@BarI^J=QC=Cli0LG%fxZxY(-D(g~EM{ZS2mMi3@i*hIu~<}qPWZLgKy9lL z{MRERU!n4k{MSJhcouoWDygC0?k|mvn0DJGKFr^Mu4RP&h1nO}U5pTUq(4^hde+yT z^YJ+z95M(l5Z?;>@;`m=q~jmZhwzOV>~e|ss_a+P8X>5iC-|ZHyoyaS^n)BP_;PK3 zQsNVbRmCRifAS&xz~tka=i~a*st=+DTWlY>KF_y*gj^6dDezp6^RGGHi_kI0-wn^w zvk9g+zPK18t!p)ZGN$^H*~PgJ*n|2gR2 z+3ya&U=W~x+;z!ji9gZb91^`)uWzHMt31vcw`Jf@@%SsVvx|#QOFwy5?%jcVxQM%S zp8BrELzf6@T^CmdEcz{?PfLR$`1%g~2jk|lv>Xhv7b~on?l9RtFedMuJBi4`7QtK* z`j>5I98~p1;NJv%uc(SYJdgsAmpp&lW7r3JZL|Iy;aw*RL;MH}LzD^nr5Ept1E5L6 zB#yl7d#!J>vfmtkbKNt!M@4B${XTc88#Q-%xwrUhuE5(?huIIE#~?q$ zrz^4_7M}SZFTC)z3idnwdlVnn4FAi9o{{z%{n}t}03s<-QU9!B;kjQrJ&*Arzib=A zal7r`e?R!oF$w;2-#vTgkKYdSHh!yPVE0G;miidTeouD%p7<8}P3Q3qo#=P@3#rB@ z0no6o=J2oDep8{Xer&0D|Ain$4=%k_|BvKWc;HD9uf@+GUsn?AsyScXM_8X>Hx;ZJ zPOyy3zLb4Y%T|NzpFDJ?dkX$CT|A`rP^CLdM~0C&;;-RL+3}^pBXp9u0QC8LkphpB zoIdLH4qZt7=4+_%G6Hkt>ugQuX3Tp&1ir-l5?%9~=b!&`E8le5_~SM80eW#z{EZkr<~v`Ih3a=H9)hFsA0>5r(!Zan zz>==5&lA~SFdz_A;ipD?Sf`kPy`SC3{ab@7OHRra7(a@S=YDH(fzF5Ml3tX~W_*q0e`nJ&>+B5oL<^h3qJ)W*JfaqAoR>vi}i_I#0k z!YD|7f=?LfI{h1#tKx!spK74pnMd`4<=saX{Ahl-LDJVG1^K|vW#3+m>w6Lk;7cq^ z_-9M!361Z7hi;&avpD`J#;fk&ihojnY8bB+Aiirk39J0~#)rk8#D6)^23P!}YWTTG z5H-*0i>w~c;W$Sjsk+m{Q1zxCFv+IVhw*L zqxd$q%y8)RyLVy#y}g)Q=o3^Pg!ke>Y-+lZ+w*xUNYlNAznFF@&PB-x-M=Y_j`CH% z$^lvuKSi$2Cc1Xpvxxe-e$5P`J-GO4M1WJWjR>^rSsC_l-?S5_*uj_nrxqsNCHun%M)IR5ylwf=ESAy?g= zAkzgKhmR{Cl1>!x_5cf@<|)4gTul`+_>YTooguywU~zkU8Mq4OEx52-Z%DGT0UgrSGTuc_|-O(`!43Q#hh zk^fW!<>;$~0LA-dALyU^5>SYg<#{>3?rXke-aF|xsTAxN6<-JnlL0+~pI8Ea#2-8g z%-<<|`qT#X&oKE6_hEo*YyG=uut&LA-Ts0`&|@`z&`o{)NBGb+^uze3)!k^dKh4$n z@Kt=sM6Z!Bx9G;z4KC-8!dLT%X{7X&=fB~1WzPP1KB)>Q*&o0^T>N=sQ`)BhiAVc{ zvC@;7AhQh>b$u+7&+wP7bhf)7|C)1PCy4WTj`Oo1yWsws`yf+j_Rv~b-XWkX1y=D# z!~gb3GoP{gj*?Gq301w>*`gvf7=R}{mVRHO3~Ww^X~HB27DRL>zvqj79l~P#C12)B z5rn1n7u7GZ_ypBAa``cqK=;N#7t1Fqj>a8QAdUTsKgA${L5x^@xX2>eNy=I+Vxjv&r{b~vg?&%Kp za`Stpf^O)KrKRu$;$N+PO0;@nc?+1d@zvOwoI*ckeNt3M@?|eXu-EgSe?F}Uef?wh zFYf)+ZIh&+u(irR?GnhuVh!I=e-H_YM3eRJ_PkewKD@0TnOBUwSYVj`&0SH)--q%D6gGAA@V!3)VyvT`n&M8cymMj{7B6T znb~;IjE5*cAhq5*c|Ge4tMMS~J6xW4!3X?n@h`xvnop)ukEiK?B>$K4k4!E}cGJEd z{YnFHiYrk3$oKn(XQ_`2 z!uLdqzD-ZWxc_*b6PL-7Y(I_?6#4fBvDl02O95re>%Y=JBjr#5IO30%KQ=A~qRr!* z60ebaBH#!PcL*C_wfaW*XS9gzqf@ei#rw$6%F4e|VQ|s!ai7qFTJxj&gK7Gcuqi$& zx`15;6#=fqyPf_}+P(`7$-x%F2*QM}Bx<#$?xApWcRWC3zN`VrKmFEsE+C3qsA z!RJ1-Ke|8Npyv_l7~LN?I6wEzw>3YSdDg@fY}yGw#hp z&s=c$wf0M5PP`^E@8Mrp^r_3LE2+@l0m!Lhqu5n+_=2%PH<_z*V`J;UQ=rj4&p<~N4 z__^WlH~BuuSX?0hmncV5Lc#ZSyUekMUj7wgHk0$5nbT|2`iOO@u;_+P zn;~vr6>=R5k^MKsRqRcFGUlJ-sajXlBd`tfd^&G^V>}(**~xW&un~14-MFhjcorVO z5O3^M7@oLmANEhC%j!R4@Tfj5g_n4K=mzoU3heRx$h^nIkmw-x7|Yw?1A9EA8wgD% z(D;@!#Pz!Pnr@Hf_ewA{I~4HBaDL{~;>#vKClQeHAT3)jW@edub^Gu8EZ>xWTi#Wz z+~qSb%)j$h9*nQ=;3#0f&{KULXaXC_ZRfS$R!A5BbDOBkEy8Dbeh>Nb*zoXUnJ$*g-R(IszA}{7~p6mvKKxuU5Ei5j*KnV2< zON$HqL3oXZXPO-18Ay@%3&$2~6{`DW3gA-^hyu)lya+cZhcH8xD z@zB-zT?ByF{JQ<%N61h01B;$NtWp0LC$jjn!bhf4t*u**dfu5cwKHe_4CAO4#aHab z^0)fV^3n{keq#bepNJX%#w6H_e#m|T39SCJ;aiS=?fI=N`wS{0`l$MsiT+jpLS`mB zK$#~rL;}Ns(R&5IkW#hxD-UGM0Fq0Kj6-_}!< zezZ`w>@KN0JO@Ok{#B_hk7|8MJ`ABYpg?8cvHCh%Khj?89ppXie$!qIf?=^l^RsH- zVl)`=Du`F{5t0uWsH_XbgX|Xw0O=MCjE#+1e-TgFEtKGq4K>x^$#>I@3&KA-i#(S7 zuGHD9_+GR8_rXja)ReXum93T(d}O3r(8rCRv%z28IqH~|}S@-fwN`)xZTe0&ak z&?3|orH=iCKWREm0}908>XN(t&dnWxCnwa_*M(@0Q$gw|HQ8GaZ^z^9)S_Bk(R(u z= zulfKm_fsEhL4OrKllt4#-*`1y@ONUL^L(oRXXXDCAAyD>2H}2ieyNwXF<_zB40%d3 zLdR4MGSeS%{>IF$9E&OcONyh>FV>^`rWUI*xq&_Qc6l9;` zUvFYi?i02R~WwZh3pCAc_%k{1<4F2*;yfaT++I3rLju zV_M&N)z{`EWZZR!JU?_L|F}LJ&wk;8wDz;d(|#B&I-sn87c1;%hn|i1HtFXfHq#|2 z!}nirWPEIYSGu)5)z*{UPpvQQKVc*28-Mb!O?}}1-rkmuZP1S#oR0cn{;Zz__oxww z{QpV+s(vN^f>_HDD-VIBPW$jr7Py#e=IF~VKFjhq(pw%*Q@`*NYv=EE%^x-g_Fa4G z#xK%gf%pUAH)bp&n1$b%{9^o6zfJnnn(^DC_z802z|KEOfYcZc9`HxP|Lpolx&AFd zRNqW`8^Z>Dvp&{r%%}R3NBJpxW5TDzAd#Z<2pb!ae&$b0bKYb82mgK7)$(7;-;sSv z|F*$TSO9;!TNof$41ujrxBjSaZ23D{e^p9E;rs`O|M$>qVvT<`OMG{{`5l1hT8{YP zyTk82_aXZTm}XV?7s;Scxcsucu?Sz~{#Vb>1=ufGzmfPB1*n>RbnSjAj~fzSY-`)R zS@!py3xU7|*h}u_fcZylGV3Xq+jT59&E;VP*)!Q}hV+%Gm&nf#9%#(>?L-X?_}_U;IV;xkgb zyi2X`>y?;xAlZlfE1~2MQpY)<<)0V*D1Hz6V%r7(0o_N2Q6t=k{@YkUw5Lqx4TgoraMwn_?2-*1#iM z_~`ll01x>AqFkMWfC5LUdE_K&$-2>XP?E+iBC!in*bk@M&mnYP9h>%Wis=Hw3oY0OYR9*E+1o|-{_ zTtA5WL&m|7)S@Bq#bV89Nk57#IR5V5*&)TBaVK^|P62Z932Xabp_&+vYvpX8!cEV) z&BM#7Y4iqvcfZ>?efWLMHb)z(pT!1IIw7X|S==3NuKR2VFo10@7YM`B-0a4ar^OHO z@97VB}-JSL4GAnWJH_C4_$(wB4#A>q$XBEJ>JfFNw$cn}9SU~*2 zXfTD}YZD1-gN9I`Cpi`5Quy%TUz)*+l3^*CqXAJu3dHa|`~I5}q`-9|Cq;&6EBqT^|0` zn(G~5f6XI$2@65x6ZWcPoV>tX&H4M3+`DcY+d6xqz z0b?V>d7E!6Yu+wCGOFL4V*oILc>XYReavJ1NAZ1b{7^7Jk1lvRe}3J%^%RjD7=s9T z-fun6K)jV+L`D7Y7ZyH(?{WRga&7rsrMkQ{zx#)*Yq6cZJ)g(=&!az5-;k}wC;9ri z2I)WWKPTU%elkDI+QNbm6ym`S$bR-yL+d&iYU_gF%`7jsCjX?NQk^yaEe0Xz2Qfo~ zvyH5MWCrG`j4<`*wT)r0jp2j;BLVEEsc+1Q(MK+KsyR)4KL|jCkpulS`LS*#;6B}fX zOi@45)d$q{WimWeL!$XsH4!^1?-HAJz8Pq4sG$2?=zzZ4lMV5PIN<@AY>{7?nzi;b zG>;(T+*SZ4f;}fpH!W1MZ{s`kFzef;&i{HXO`yE*Suj`7E zlvnb5SwdTmOFicLu0=|Oz;OLUmyq`aA#_AiF{u7Z!zCJo*Mg3BG@GudI@sX@<`*8ok_}OLZC$drh4C|i`#W6RVK0P1WftHu6U+Mel zC;X1xyUqT^{~`S8E(br&Kc)Ok*`K&a2JSno06I5+0S@3AAi2qZ_TxX?d3a1K@T2pK zgNz2tP^OcyTt7pAEy$CTv6<9$@%{9Nye=8_2NHnr!SL`0G*bCM__+1|@HaGGcfH>o zK)=o{0zT#NOW`lW_4;Z-xaR)m?EZ+4?&~kXy1+@Z8R*M^GPs&;#5bn=)``jSG2u``cx=j^isuW&*+c8k9`6f1A<@yAF}l;->s}aCGo-k zrz!9658h`1h->ao*mPln-YJvcEJJ4mAHN zlA(4yD^vx#w?i*FK0*DNdVeMAUyy%Sj_UK;{9Hr-F8`nSWAeMB_~Rf~R1b>YC_g;e zl-hnOVd(INQ(k-)!EYt#v!p=MA07W2)-@}%ixDa-zW@nIZ(1Hg_!j%Sw=@)P^){v3 zdo$=4EHAmXSVGms?A_Xr1%MGDJ7Pcit2KXdqS{+4E=~?ke0>1^kH)d;zu5ynB|u?K z{4e#HIo8#m@7e!35e3btX`6>MwczVg;bwVOGiVp}}ihT)i!0pGpRbtQO`DfML9A56~-@5z;nB=Z+ zd?r`;bE4!5Ko;m{vB&PbYvk}a?vKwD_Jz=AME}2m{;z2-s>pfUH{O>tMMOFZ*IdrV}^(y$|=Hx`Cp(mXkPfv^O=`3uRhCq zB7MtB{1*>~x_{XBdvR4qqdYt#!194Q#W}Tr%J3)252U{W@t}|R@D9J>VQeSHRs}Ta z4;)4Wf+nE&;}-v(BjS%(;+DToWm|X$uK=9O_9I~xKhA!u&v4Ct)nAPC6O^ce-QShC z+B*?s5l25ib!X|&DSQ-<(dUH_AM~SZj)#B}h9CjLh`xo7fFR*Ly=?Ry;nyyRK>h`w zlRxMEZMtioKK)h6|HOu->srBJGzQ!+OFOO(XtRs&!9U}wALhbKQ_5dXB&+uPtML!l z(9hII&hIP#^*&y>FgQK;KP0si*)g~+fFFe6r%n#<-%E9+C;T-1>*P7q^3&=#yNo@O z53)P5nS6G8f3`cwYkkn2g`X@E!jNTO3^%4w(AypU1#8pcHMtpOU*nt%Wx9NU9@ag5 zy<89ElI+K7bW=_j&}4{;7*fE0k|`sF!Bm>0J& z!u;oLTDgd6haS3>*p_9eRe8Qdv6ueuqfIw-^ujQ{!11UrY*iG@TV$U^@r^OHA5nY@ z^Sd^G1JaD**HFLx6!;WV$Rr7ju=*V;KzRFYyT|T&ys>@q9|1MsRd_Bk0kz@6Wi!9f;)-@FF9AuxXvqL;G;(0>ty3`5{;le zzsHS91VSic5Qoq}bdfI09~JT{@yfe{>!JSf1oY>?hB5lX^p$1G!8$$*GJU9!4>tAp z?;uLo+xW?E??2b{zmUeQWxD%kSM6glr0G}WuT;1xIh`$_}FmMec&EzAK&-!TAM4o_uDZe)F4Ozb*)wd6f?N@+qo+F!j;?Nd%ZGIhb_wxJ3WNoSf;9zD*zByjM>_dH@Lynm*FJ5ETtGIMmBaeh+)+K2Ew>|-@MhlM zfkd7fXQj$Q{K-CqjSX3|9p7l>DNYgGMq4tJjr`5$^rhs@K&=0 zlR&fhZ+Sl2hr%9g)APaMo*q|>hCF=2%CF)-jiUd20rIW;XT`qc-atFB_)~1_{F!&o zoynaUdMB5AMeAb&1Velr@!{q_2+94O!`yqfBloJUSSZ+S+^IG(4clt^30DZjAiA^g zBfbyypw_J)JkO&OfA4LzC)5NRfdsaUex4(P$>`nEcKXAzzeqtuM`q;WbQW&Bij4unfkX_V| zwCO(#p9QD`QCWvq;RW>#{g@38QMAe4G7cJj0bybEFYc+W%PFts9dhfNwqLol)~L0R z@1%dy*w})8u*+y{!hh(=q*-DY%eN^d&9qQjQdJovaKb`FA$Mw6TYbWi|KCa zFQ(Q1$l)vEz1p|~PWiDo_=);oWrvx6>Ke!6b1%|gK2CoBn)<-5K14OUTqvAr4*c=q z{lz`PuQ!!$>S&-2+>XAH5vYsAgU=K?JQN_&xAzH#4hi|&_uezk0%c}%*;@8XXTM}0 z<(WGS z^6Q@PQ_HUpMZR3#HU%%O=r;L;ERwhiNbs-2e<}p$tAK34yCopKh-({Mk z_azdgU}<(gJ#S!JPi&$4#G~vMKHv1CQh9z!kFvPPcv9Km-pPs2$hhs#(ZA`#`(6EA z)o3sPQR8W}%rsgAjF)FN1^?9XpG$nh-)euf_4gIvs}#|@BYmkp`44MjBmf}aXT=6s zj7)$%cB~2aW+?K;!4ZTN{qa0PO9H|wv~=-@ve7%PvZs|b+->d#PxyQfz?H``jhI~kGC%iNhF&Ed+#8}zMX9;^ z<1=x}y%F*~I?6xLi35jV(JRjW?@Dz0G`5Dq*ja}EEKHrBdf{upP?zVfoHqWzLWV_X zV~kfPR-(UV@gWLtcm6Zvkw_cj*7QXCQ`m2mUXgsf75+d0B|>Xr4kYA~sE2tIGDw&N z^B=H>2hG9+2U>^joXd4|PVNKK(EN4xZOh$}$s8KSfPntJ*LSrx z|5|pK#Sg-{6Bz|fa_~B28UgPunq0+q04}Ahp z7?t|e0~TYNn~$Vj4JG{ zK=}9?*pM{=7wE|;{w9!Ow76U?&IuC-$^9q z0e&L;i1EWRXLUyPCm7mm_OIgmJ=0BoCd7YNE8+~E_G^Py|H<@A;+O6@%-OMD(C<(Y zsouvUSbUY@7nHtz58qV$1f^F*yg|*z7=GA@b^<_(bP8avSI_U_AJ^8eQWJ08w|gg6 zl%H?(8ySeQKaGAP<6QP91H{xpWm)GxGyN0(6VIYCWtdz+e`X;?{+*yoYKg`N8W)jI z?^k`NJ244A%aAfZ*Y2nP2JTVsB*bd?iTD~HUa}tHKiJ=sXvj~{K)LG}w`2TIJOn1h z^_71ylWgp~pc*u+k)j!FGp5dxUuJ@1!>Fh<5@9PISg?h;2ACvz| zJ>;p*XZ{z?DR5ZKjjhEC!%9^YVn5=r!91BWi`&IgvV&~%3dVXJ98--o&VH*0j?GM)+KY!-; zzW+P$SJlr|e{Hl&=ttFE%tTAn%>N+mUduyTMr{2lo{s`N7T*OzL;TMg`_J+RJj4=& zL!Z^9`K4tRBr*fWgPUy+WzbKtz8yeiZnhJWNAdVRe9@@nNA`uRHAsr;1Ix3oF8>d+ zjKAim$;O}dJ=`Dg#e4!4KYDY1%3tEY{Jhi%ek&4mYo0?lOLn~ZC)8dTe2C+po}<0+ zyv9*OT$YC(#|I!Ow@Ur)uIxnf*M*<0aI5Zkp1qF3>-wD+WP~~t9{Mb|w(Z_KIoZ~} zB~5Zo#17>;e8iCmN*2=*<_{ASR3N3iZo{K$`*t#s1(5YvQw~ zcwQ!Wa8Nvi#B1=RR5CuCZNty1{`KI)7bl)h#D8OIz5zP&k0-m1#nFSQap-yTWBk6- z9Ux(iKd#CbU=&8td%SfrTcA88{ckM4QJO{xE|>khNHq$NZM&7UpNpbA_Kat`{C6|3mT6k%yFIAN`(PyfV97xVYtd zouBYu+j_PQD}GZ7C=hI=7W;#~_2^ie9vvTl;PBxG4nMN4G3LcPFO5C0_#W0dDmZw) zE=qh30A}ZLritrIw8HsgA3XKc2f9BJASSK;aO;+bp-&_3X`a)#5O{mNez<59`5rpu z3m3a^DC)5{`Yi)vT*Wr<$egCeX+P*c^tS-|&?>i$tXJG)j2$2NALGZGV_CS9^Y7do z**Tn8Cuei^J+9GI3eMfo34h^BEDhg(DSV0iZN=3}L)v%>GbkIv(m1NRyu3_-U}sOd z{FaG{&m!uuUnMusoLO4pALYmSlwCsqZg=|kZm+WOAN$Y#!N4#2D4=ns|0L{@%F(UU zx`8dn(EqT9-bFz?H&6In3FJ`nGg7ZH08_?N6=HyT%Sc|MKO;ZjSH^l(naAm;YxHX+ z07dx4JVgo7JODJMze$0U{?>D#_>t$6{;_kUar0*N2T4tRJ~0psn1OU#CK?=$Ux8j-}s9Eo^jRKzCa(N_`XgxOgB!eq1F;Pz|FrzKz9SY@gF!Kwe4n>IdmMhWI)C$S{_=%J z2eDD3UGbZ*l*FG4g}Y6E^t#|PV)8Ef2z(b0TBWw8KTfi*Px>3t9hor3_+9l6`oDA9 zOQcn{Ca>hAR2KFq`(+t^skiWB_*d@?zYT$j_1uAi6w%ib=`-&BQr9d0kNVP(*B(#S zb(MuzU0C1`$e-BbcTvBUCi50rkK zST72GnR4q`m#9{p`zcaE;2KeU4*Gi#vLCh(cL6+BKOM=#gJOh0R|h+FfAFwv--kAX z%*$QUFAg+OfK=#9hvjEi;XvF#Y0RQ1WZw*7;UqR6xA-23F_sgu%;7scG7)06i9Iqv%NYp*}U z=unM>`l0Un`IjodfaeDtp6PT)&eVBA^5ejfDSooa5Cetu!obHqZ*2{_@AAN>;9T?S zf^&YhFvNHhU(wpye%oYgZ|~vt8XpvdA{=sIN>LM)~VvP6jZPZVL)~coX8Vtf>)hW<+`)%Xn7T+BP6KYjIaqMV#zQFZY^BW@luDACW zghudr=#P5IQ$~Dd^U0QJDM7rtJ)J!__;RKz*fyBSKo8O4HzpweaHM&_1tR~`wf%kI zAJ^aqQT#Qxt`d`buiDoS{iFno!(K3eBw-DN=)a)(L3Pbo12yFjP&_ZO;nCLiP6iSE zI5~f=vb>Z}zCMGA4l#&+487g>uvV$fpP{!RA^0Q8XS{h3&Qw=`-fMkvasJ=@YGLVx zrNyVdhQ6CR)tVl-e;o2jw;?~OiHDp5O#C_Lm;Ook$yQz#ABujkfQ>X#ni(Je%f$?R zVK${wpO_#znQgQ67iBlYXcpQwO)uo5>Wz7=9<86MM}&!#ORb+&X8$_!Cm-PIB2e_b z(xLG;vu`dfedqP1?6C5O0BEA_FT|I!9@DLV?Sy&ir|=Uo2Jr^_iT-7bf#tnzFw(!k zd+@=zZ?Rwa53FEyzbTFu+870=Rhly0{sbjlzL%hQe1yR1#tpz z;l`DKyqvTg79l;l-zO-aw)5UG3_X6QKE9*u^8+5WfT7>$0mlxT|1zTQLUkTP6#C}U z88+0GUZ#`V5WvD_yj#YC{-mq;1HIdZLw3)ip%^&o>L*6}WkM_}KNabh8^0$Om3et9 z$97TT4*-a}lYfUpxrM2UH*g+xwgUYtHb<$E#P=M$3;I%c3@bPI!xMkl&G}>>0Rn&Q zk@Z_*8x&7aTewV&1>vW`dHS!ieheU}uOFUC&*c;d;WyyJcc5?G(Ztrm{QTnd>Az>C z{Joy~BKgH0Brcm8<2L>=_M_GKelAxioJL_oKI{3qMBg?~ntxsb;ccF{pL|ikPZzH; zPs{yNAV$WGbkvH%8!6A^8G5N07D!&|r^6Tcg?pW8#QN<69YEvZd}vM640F(%D^R6C z`?YlNf4KS{|ZAI0y8q4d33l$D)O`%c4usW1FV`lpT&NKgI@o-^{s zSl}ost(q^qP~H&gjp;Y?FVD@r{>Ft>{YLezin(^;1Ka)V%^}Axz(EbZ4%A@}{H;7W ziI1Lz*+04&f8e7^=e6w{{}KB}^^+-|tl4WmA^j*|gai=P!n^QaX#ud$$_GUK{WPaOKkofqG>;t{+%Yed!s)GFgWtlVyb3O-AtXI_!`SW zDI6-qdA^!Q_sl;&yZp!f%P3^xZQ!Tmmk1%c^&|ct2$c9jzkT;aYa0Nk!y$2Fi8<`2>qlM{b~&Dru1lM@O!x8fz6TLR3BC_Zh< z@V}x7DG4g@n``2a=n zyOozEK7@Q2%9Sm?pYnFyL)Hd&MsLOA-pOxwD3`*)<)t!vxdqWu+0@qmlQGyyrGCtNn(ipL4<753JjS*kF+w|-BmDSzQFZvHG zCu)zS8-cTM3()o)>5CP92YSwK&)vM6(ZN5U^`}RiM-I5>Q~$5SI`wMU6moF|aE>WXF_#JHURvZ}k z&*+d7Fn)gXuJZ%Uk5n{KVW|8^*PuGGk5nHQQEf@8ir)#^o8rUt*AadMLI8bYcvce~ zHu}K@o;!K={yb?zl%s%VPad9v%$`^PiPbvk4{85j>5fk?D zCi?rL_>{Qe|1Ddm=s%OSse1ze@kiiq&~6{$Q+T0wHm+9zC9eu{kgF!a_gIKFzFkN2 zngk`0+4xqoS8zk{!XFR+ZOxA;0xKWI2Y^4D{I5pw0p(049mfikLX>B^UzRestN<;= zXOSPmDcnE6%h1zoJpXDun_blZz^~d{r`uX@1D}P#Z0?Zmu=};*`x6uI7bm{>@1O_t zUyRE>;)gTC_jCJ~lkX;z@Ame-o6P-loAX~XzsLuEa(>YV^NaUWU38uOA`Ev(9o}v^ zVf%xjV@t`8{{R+0BmUu&yTfEE0K3EROI8m0fx=f}Vmv%q-YXZ2db{{^;cwRe^I7bJ zeF?bL9^Ds$kseF^Ig{T&%hhmZwmA5I@Vu!RYMZqVPH-pK_u@~c{YU%JU+@r9 zMWEENb4>MX%>APP`>;B9>L>93riOy~FRZ|h7pF1{_(DAXGbG}8T>Q}jEDc`vr&#~8 zP~l(9zw(zESn|_I;lz$eVgJLEw2_~WRrrILXYsqZSQN&S$rPy1BK6C0$Ta$#=7;zm zordGde|HiFnrLEGIPlnLK_K%j~K=S>AHoP-58a%HU-?=j0*85u>Zw(usM|Ec=<@gAR| zy0%Iv_2GZ{QBaImJhdIdxJy9Uvhi{w#Hc#0DQdWz71gl;ahZ8{`YQytI5lQ~^Pw5L)v5>jd`q|XxY=M3RuWNyOi8*|8<{g&g`($`-e`P}b~+{s;JGSG8C_%6upKJLOm z>O51F0AUsJXrr(7`~nCo56X7+c-E1wzk0m00F)m*?fT;)AQV5w+Nx&9$DbxTNcy=> z&e~(Vap=N^AzEezm4s|wR-yQJqJJb=9??xwPec3>oiBTg0)E0@BmW6W7Q@8Q)_;%V zfR_K_S?At7OzZdJe*EJHIX?Y24CPM<^a*r+v#($QT0B!c9(1RNQ+uA-(~^JrsKFoN z*9!P4@;?&4p71*b_ve(pee=z`w+9YCT3#y4MIijixNkst7MWO#BJ@tayNnJ~0=S~X z?{-hL-+c4L2KWQI*EvqWPfoxgs*t4efvCvH32H?Qo2M(ncRhX?F0(RVPZ{!sY$!#& zk$=U;PV?&wdFCe{&975~lNwfHBCTk4zf zN0xwO?5qXPG5K4XAo2`zc-&r@&8(&^Nc= zE-M#FuKR+uB`GowG`~jSk3_1Tj@b<1$whV>jRlpzEQ&b@SlNRSw*Ei+=P^j?2!5A!6z+zS_tJ@`*sujP5%3}`@M2F z{J`)bL+kfic+f73&!~@(#g~eUiFNr8dR}bEb7fm7UikD= z5D3#H&I56{x9`o*!Fj~_?fnerZ<$W4YfRlS*<$)d4#Hh~ex9rzpN$#s;t$r|fAfhJ z0zd#jC&%Egs&8ougyxR`**zZYN9y;cSUK5#bUpT-3r|2nn@0c)uGt@N{xZho)&0Q> z|5B;0-T$%28mU*mdVJ7vUvEwih=%C4%mMX3FQUE)UGX1!3jJ67FS-FMf*t9H(h!@$ zup|4Q2tf#|OJ`e2yp~h!OOc=4pVn`;-v|b`POaK`zVaFOgha^9eb&zJQQ}59T(CI4 zUt0iPgfqhAI6rF|^WqCoFe%f0x3b^=c{cm1)Vq1v*Bk@>MgIKtmY~b|IXm^2ataVd zo^e-7`?NW<_&^chYe@gsDH#lXM3;q2L=4z2ix71U(m221WU);BhxLv2_-y3honQJ7 z8a`6!v2oj{_@DF}aLKUd&%ggw{#Vg{6mb3l$`&ojevV&3a$T-0EPx-PprYO0M+DTw zbOYZArW!tC#gHSC3RZQ=}&Vg;M*63FXwmpMbN;&}nrcl9gK*uZyZt6E9+ zRvkO8FY|iGZX`spX!#+Uqjz$-cRD?uAEHe^-lhgI5|2CiKKJ(?|9!t1(^CEc^e@)X z<}c}glCRZ3^{sNhcK64alo?|kZ2fbfq-*kTI0@_{-oUDtXyyE#*sDgF-!CyQ+(Gow z{W~@wRv-oHS@c`-cPJ9Zm(gzza(xX;P*eShO}~s$|FAJ$=t0lDPD~8>d-eXYjTv88 zUP@CFQ~%kDS?(S^f+`jDpY=S_qqBRCi@x^oo0}i7>MKv0|00=Ef5h#NHz_{Y>RX>X z)|vg$i}NocA45(n+hK2%---VS=+6b8y+?U^{2y9BXfF(dIO%}s8~dC45+Bt1)qXc& za6iREz~5w9={>9b-F2CCsoRg8KnI5ZL)0ttC!U2o>iLzv5=`jd?6=-{400GMoFRG@ z^o~48*~4X-S7Ys|>th>FZR*hTBR_&#t{XQ6_=5*9%V)?9Jp6+jz`w)L1%fn zQPe60ot4|%Mp3KO>{Cos9)l^Gg4|xtT796GWxm4SE&c`tIjWx)%)F}pU#s_5_ity1 zg6y{2k9zdyEzDkF{2xEy{OiC^8M$wG^-hjy+}?+Jc_mibCU<$>9fS|nKX-l3OQ5{) zdg+yyUOD{--_`o;iays_{JDp33IzCJhR(eiV2fb-@sp!n^OKKCM3Tk z!MMK~-2*ZZ;LPkS3M$X zczCqg^%(%Sg-ko_L(;7a?om*DiJW6t-=^L{pQicHqpF;I6qKxih080r98?#c`A;t? z{vuiCk+#}-OjZ)AkR2*MgPtys$>`ex(=5mUb_P{m@<}g_vOpz2Rlh(EG~qWN<}aSP z-rQ}Ngn@cdzU($6AFlPUSp5^|_v-jv>!146N5No1&f$!_U2R$e<>>-=(^+Lp<5DZUD} ze-H9q8r=2X`1nM1ehe7^Ba(mLjzoctHn(u(_^fY6Ku}pZJta0`xT2iHwcJ-lWyCe9 zfE)EQbpDTjx$F-s^yQD z%B7LJ$s;eFQhX%hqc)%1p??F_!ZZAQ@DpQt#uo5%LmtlDbYkxIzZkr5&HPCJGCCHb#r$fikm zXUChJ1;|Ym3(q3hpdqbq+0QKmh}G+(NW96#g^kTsq~8i3gF~o*vWqVRxrGH|UMqi_ z8wU6Ng59U&FKaSbc;;7?dFMvZEXe~Y?T0Q4l7E%j`Sa%9dr$V~`coL_o&6)8OEUDl ze@Ue#Z%w6cy>;^WRO*o^|9Kq(Amaa*Y+e?|_(wi$o%r`bzNtUPGax@Abg09jwD67W zj%_z(1KRgd1cCa_wd5WmqEKvd=*k$*Rp4WS=LIN$ls8M9v;fl-83;Z+Ib@9KWnUyosUBGnT0XJdXezKO)# zyuyRzpHP0-c8O0eWGW&I_%gi1+|0sv8sd)=zXkE$dCKmuTDR^T{jzkT_&*jX>yx`P z4hfH}h0qsrIa1$&p-^98E5>~A)2{s67b@^K{QrjDOF{e;@hi2GRzMthO7zJrKC#+f z&g36A5LkKNh3A=He`|~SUr_+e;e)0=M8%(k53;CGO>U3c%e5e17$FzH!awMjU2FSi zh2HEFWJvv$0N6yWm}{1P`gr=|w|yFVa`;o?wFiU;FTFA+nqz(;aN-BhSD-**E*Rf> z{;1XeRAAlCF=5M`;d-ZcVZ3u~8-J+>oG0?n3`CkKYt{TS^5Yv^^E_gsDR&@W#elpje&wacnhrU%y0)AgPd-lrm+5hb#_=8&? zXiv1Cg~HtW_%1Y1k(_5g8W0;CfR!2`A9xz+rrOMY^YOn4UWL+xZ#%c2bs!eLZTRzc zN)TIqLIM9c@SqI5v)lssn)sidpZNV20>D0Ud_E>37;_ald(tdK)a~hZ+-+v^!4}OMExL^nG8Dmt&hwA)K=v!@j|x!H#=`K$c?xh`;)U~ly(a>7<)d8us>kvW{385?jkDx4 zK~p-`ut%f>eq5=>XUB4*Pn{x=Vouk|XPQ#%MNW#8wEv9uYMigcYB;^|{2DVC`OEm_v0-uF&>(mN@`v~fv?JU%WU;ZITCd30)Bq9h4qxD)%LIWXgJ8U{ ze~;R}xZFkkOMYU<1;T=g#~&I~&-Q}sYxrMFOST^W5(HyQ} zc`3zNZtAcCcenHWWekYjKNQANm}@qf^F-V@g96_&Oji8m_=P^QDv-0t?wB3*F12(Qv1QHMKq0& z3!vGA_j~zxYx!fX$B8FVeZoI~DL>x)2m|-8y@pQ;JZtK|rN6lkEslEMdO!g5$X z{RbKG7xZ6+zm18#nf@CMf#kdDH-_XhnkFjoveuGGAM`1Kf>E3}66Hgq0mVx%t!84WA848$L-wv{&oMPr|$ zA6RWG_xmkI-`Zs#eOGw68LzTl<)73y_4Z;;{jAYyoLA{tfssQtJvcw5+0KZvaGocqxjbi2|_g2ucJWgw%(HAj~I7<^42q@ z-ZttD#3_zAU^EUTNk5c>9B^yqKO}q^tDD+I_Wm~GhvWg_>9%(^FZvS;x@d2hsCXTL>$Gtr?WcwN16!+}{nN90 zOTIvVzB&-xcvAfRR+Imx0IbS?*vD#rx0a9WPr!f@5Sg}c7;= z``xAwi80f>MJ5RR(P@Ta@0wp8zl##~`G(GhJ+bw-OMa~+E}`GQKJ`ZFKt=d`JIOap zbvsc)#JAF}ueG(N{xP;Jbc2!p9fbT+VSpn2JM#Y!UZLt88>WqaH9e)+$K+D$^04tQ zlV3)EFj$EY!!MJV#(ad&a(YLY>|>yH`X~TimlA!_S*|GI$x7!di~tMT;E8x*kJjJK zq1p6-V$!_=Im*U8S-rSW?SL{r?HQnd{8pO2^Y!%ueR6ktQ$AA{aQFf+S@@ERKSF*; z9$Wrlqr3X@vFxt??S?<8eo2bwGBc9=EA?Ku>_q^8;!m7^Gdzd|d@u~7-{Wx>00qug z_Ya4K(b4h4SNG2@HZ^50Vt@PDHp>rOt*=J`ZMJ&-p!)gsJZ!7yclIv$9O^ZZU4=LU zAoj`wzyQVj=8kt>cS3-N1m6k$gDR-`eeoUGgQA}dpOk_`9nYltlMTl_t}#EiQTCs% zAWCQD&;+*+=Mu4=nm@6?i%WO8{I2F*it2X(-0H74c%VYo;W@&Ib6Ld?cnlx#D(_U+ zNv)t)G8w?8D7-}bowJ51u=o!ym+MH@8Z84V&VjVHnOl+AR) zp5J6A&+qu3)GtUN3|)K?tYJH}qOFMjrG@Lj-$B!_Sgpmz^zN}1X}8kPv5%A3tt*N7 zu@mSo*Wx?MkF@yB)&2qr7T~Q-4NbRl;|kA#|1A7n?}gsKLj|<{Wy zG)KFGJ%^HwM9B2@?Knw%ZHCtZK{~t?|496YhiR0{S$9?AZ*cEO{yr=F9Q%;|o8y$X z_fy{aO_4Yn`H>Rr#UDn@fToPgu8k+fAAAJ}F15~^|5*J$7i`R<3?fk$$H7L>~mrh&% zXpt8#M)GH6Bkj}pNp*5MD)NDab$AFTvf7Je)E}TW^}@e+KN{h+FYNyS`_OyBTkWqy z{j}cVfArq&qX1#w+nLN4xWDPt^yF3l--q|Zv2mM!N`s=1TjIAq(!ZPd#=}HuZH7cs zqJP*2tH>4@@@o@$bvqBYx1|{f=iiilTbmrJ5MT2(?muo7USSag2}7?d9f1p7BS8^; z#3V;Ud>!Cw5K2FZ2+&`cGW-hZ5@fBtTkaqV5c|=5oR1wc9rR+2BZm)vp7^uFlfQRT z`UZ8rv!neCX8*kxS)ceXcN2QW%)9(PjRp2bcE*o*Kn#eWmOsQ$$e zJ^yUIM1`@%6gbZI;nN$ucp=*rZ+MucLwFofC9J+ThF&ceA3%7$C|WSxSg|L%!7g+B zU(x_G4aR>PhT?e(VZn{H;S~J?QmOaGC*C`J_?M~nH!QwN2?U6M-qEc)iMjqze@Jm3 zv|nQ2zcBnciy!gHtQn^OJcVnzjxsu8oY(m_Pz}m2)3uW{|3nGbAA!)!{;)5=zop-t zCx@zTe<-RHvsFfnAK>3ZKX16q7!xKlH(P-}8~V;|XajFV`B89#n0OGJ$9{$PT<7OQ z)u567KyM-c4SLjH5}UqE%4K(O2kPY=L3dCVgZ<{k+5bWS?SGlQI9oISQJhHUa$}PT z4C4FO;LE{*({=npyh}Nt;(yh2Eo~|I=HI71W;)kO5!=)@MpyG)7WpC#Uw#??pXdVw zG_r4$U%@wY_mpoS(266-&r9w^_B#Ku?C13S0Zbc78J<SSzmB z3xAz(7q#En{K)kvz)WC-j(OGb#cc6K;%i8tLNo3Q!=8`CX5UH3b_e=kh z*0%JPN84{yd@1Y;kM;4~xie>mh`M0N!7uI{EsrX|EzbD=tia2pOC(>w$JBn2^dLka z^NZaN2cX8$$n*3+1CyS{dKWw`2FUso_8!!-yT4BZ`wL#i{G-atYG*z}FF|}(gk5UE zVb4Y5hLS_-1pbFrkI*tNv95){^(-{BicR!mC!5d}a$O#Vu|S4V<9D_)kpk-t15J z_4oGQT;lvDe~T!&)@9y9eky`k_N$ZcxYj8F<#B$K?~?zCJQT2=@C3dk+E}Qj7w#S) zJi+GQ@=GEEgj-?wlwSg!`oSgab^71JKb(ID5AgcSRNf>2fzuei?$Y`i8-Gjc0ror4 z3GNRQpZwgW_?=X&;RNU+R0@8#^Lb#9Tlk|eOpg}-j zcX@Fey2K{>b8aAm)(dRt7B08G=f9`=R;g5O6c&s2MyadpFweK}K>xh`ckXx1zi0X5 z)?cSn^?%L}NxExWHv1f>_=q$O`|}X<1z>Kq$7LMQj%c%a2_3vpNoP_(NSYJ_WQN2D74{%KaH~d5Kg{%0X zqb~##YPigMM_+s;@?V;LjSG56Ib{_5g4zi;cDg)aSUIO}`Y z`5N9~o_}U`?jh+9(tyw}qW)bjK2-j%p@RAYeAN`$8TdQ-?eG9W%xE}ve`6Ly(f|s< z{H)feaAA9Ro3gJebg?E9A>v>U)5sD^Nc_=$Y*q>)r4!ugn`qz?Qh^>y`Md_hmNKdYJu=h^cXZTJ+g$A$ivo!D%9dCq# zh-Psp{>BK$yF73nJ-4FqFRQXpoxX5oEE0&i(S41JSbvKYE&NiQQ~wqJ6bY7*2y5AT zEFOn`YToFs(KxFsGxE=p_g!N<+p+(4-qX_4H!S&7;TmspnejsOd$D2}9U0kTAecFq^ zIzGVs=wVr9*g+v0i8db+xj-+q=Fj_tPi>!Z}0R_zG<+5eV1>1>iPdW zG(IQ^qxtuV&{BJK5J-(*SbFi|>hT)}(NpqAuTB$CxC%`~)5P&*j^CU6yxagWqn~Sz zr#{q8Hv?gU&y+;p0T)2Yz{6hT_nPK!|EM}>j(lcV@y*g-=T98@+DlGN;rvl>pXu2) zKNj2viOqiieg}OJTqhlw7xI+sxNthbhu0IsXtn0QI}C<``bB*%8~nsdSTO^!iuP=& zH?W!9_R%Kj6X!TIpB`|>6^_=JDB`d*fw0K5zyp~(I@f-^Vld5vY^dEFhu zyW&YIw>bR@<~=(4)O?2*=~wE{N$_T@QRQuNA=kf_{@3mA^IQ5yue187tq*xro|#`M zGWxvt@88GxbomeLyy5yAcHI*&{2osiR{bl@I3dE)f%EJy(_r|{Pl4i>9$W9}{MU?6 z@&pYoeSh#ae2@?U`-yuim7WVF<4RvcKboBUZF7OEgLgaR0XTqY;H8m*K16u-PBwy+ zNx?V&2l*W@$$qKF_b5cR}sy^i9>Aaqr+| z(}B&nk2t7wVEW4z?<^f2g}oKDK5YKxlZV2U#Onip4em!#>`t^M(I=C9jsBqeFydPv z0APTMuL!vRXbJEK;c<2S0Q`ESg#W`0fWNqOMD+&;nE%G~jpT1oT|xrb6YBb_Iu|Ft z8v2oKB;o@;?c(|#D~H*mh!nEI){prwdV5*#q{&!rVrOSR{!{%95Vv7C)6zixt?7sS z?OZbX;%C{dz6slwR_yN0!p5*Y2Nq>lNsa`bMB1Um?651{Sk; zrB~J-?-ATn0<)VDf>e%4etFXhcKQVhIh|M$PyQ44UhO{@NICsA%C!RIiI9(-Djga- zeD}!6=-ri03m5UMdun|Sd1@M}1 z1qeT}v4V_MeS!v;A4YwZ%mIzRa23c*55oGE@=Ofy`k3|x=zmXESV{}lb0-x9Y-osCsc=0yPTf6KpRj#AeTXl>aBzNq2T?F&8*up1Ffl(%W? zK>DXUkzWw%n+)xni?iZS=$=RowO2--hOFP{c%e6Uhx`HNmhbHqygG6?O}+$MWZ+xA zh!>!Lw`M=*4K+1wgkBWC9I0@HncNTc{llNZcWrkk`Oo=ri&t0APjjhst1NWaK=;G@ zdA=D|4?|SqzlJXb^(_N`P9T@f#o2`;rip4{?8R2ggt08{htiu|I8G;SYdt{A+ry>e7dO|?VrUy@MuI= zlXw~GR}e=wpW9x1!2Mpa2>Rg9GOysjY;P?Gx7~u5=$6|8e_N@%^3+pL{aef5 z!GPLf0aQCmhp>;qk656cXOqS#un$)E1J6@Q!>d_z)E^{?QPo9KitQy=+*@eA=~ojm?*r3Q)${?GlP-tW+7f8$Q#!>Y=_Udh#RE4?gZ29*3BBF~HU`q_+) z^PKoc<9Eibr1wM=*@UW`njUiXt%b5a_`uke8q+Qq?tFwCF<i|b!?SIk}KzjX1biOD;3lJ*mN zZlf+P+xUMbj{kQ3SlX&3V=Cm1+R3&Zf8Cy8PNF`D1+t&Vbz(xDM^Bo*JNj3>op=9y zrDk%G0jlaJf){mS2mX{ybk0u*)pIMx<<)`zXe_r#e z?d|mP_PKXYCuh&<0Yc&a;+8G1`HB|c*zn}8W)D6n_%Rq+p7v<$2&)5yho0=c! z`F@qET|*A@Gd;Xlzwc92?~nYHeeJ}{i@J$pSl6eshsS8w{d7;`K^-tGE}We^`{X6b ztugVvH{SS`R)5vr{HFS!vS?JPmxl%LHhyK-;|U}QtMpXy^Cr{$E>vrRRqW+u`ECf7Pa@ZT+5}?Q#pO_nCidMJW(9gh9=mltov>wlfej`{CZy8&Iq?k=m-Smr*yOR-L`(kmalwSJ3c6Fl^L`(^7Ny0W4x$O8V{+z(U%^$ndP8kcWk*C*Spe#3qn z_Re4JZa*8&U+Oum(+@7#`E3Plzdx&W^EUsnpyN?nKKW$mUAhCal}vV~>W_U@9+vu8 zuV(XC&AM!M{BzcL)n6{LeuC!tH2nt^r~0qNOFU{^JOvZd!|DiK9O!HQSD)4T)xrJk z$p<%Yejv&E6-^uL`9MordUELbODePQsohw;s?8sC{>j|G`n^d<6w~@`u(qpS*IUqe)R{h z+4^ZaKcM@YhIN0F)=xH+-oNq6h~|izCKU?d{FI)p_sBiZ=>R=Rs9X?=oFHQ@TXf0b@pgqXF6_a zkFw5*A-q$hfqiZ|Mm6V*ny*i{eK)2q_q;G=}~ms`Ehy(R2e2M}Def3wfUFv(8G zbpW(|?WdJ+5hwl6lP8p(*?l{A8P2~oD&<#y&!#C|wb8aOOped!?7KZ()XvZK8uk5| z|Ii&OfAq4_H78U9HS-AX;rUTA9hyK`(D6?;?=-*4!ku;XZw+uI>|5$VSl=P8%KYo; z8*}$Os`cp_|Ehkxy?AoR&M)W$;sbKObdTQStBUK$wt8~E4qE-uJtIp+S6CicoL8P! zOa7|t&w6?PYv10N0(SqLnOp^R^AOY~8`xc4WU*j|PIR~BSE-x`=^Lr4SzfuatMz}f zZ~B3{u!8k^p`aopf4J_ckKz8mkZxzUw7%7@pKJVR-00k0JNy07><3i87}Hf18E1uF zeEyDhKk@WM+dQt1Rh`st_3U3g{kLHAM^(MJ60Xsxidw&|s;dNvC>P|ON>+cLK8N~i zf-V=&Zp5_a9VtH+Z%-Gt@|Avv_HB1iUAN<}`sv=m8&<3aq~6Uh8(w7pOdq*0>GY@O+o|qvF@2I>YIWbJ z>iXx4f2Hm3n9$81R)Onw_@tYz9`{S{sgUx}=8L^Hr>Cg-gil#nqL#|2^w@#u=^G)&)xK-a1IA z|Maf-^yas3zM0iu?VGSv{SW%7eOf|L)j`+{_s?l3cc}rY{)LX+-yr2QwYMIi-=Wz5 zdMw|zw)PbYy8c_~w|b9l$ogG>?7H+-^<Co>C_;%GRnCD_=7>4Z`Y5`oOH#&q@B} zVyC#A^k3i9`30N*+32#XkKq6xXwdcLW9#Z;m`8UShk}|I#+UUp3mQzMqt8GA`Um49 zT88+FeZW2rjDtR4AFvPD2Uh_5h<(I9x&rV4KDc$nzl0C)!L1|nXZQdg;DajwAK(Lg za0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;Dajw zAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV z;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0 zgIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC z{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4 zd~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lg za0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;Dajw zAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV z;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0 zgIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC z{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4 zd~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lg za0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;Dajw zAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV z;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0 zgIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC z{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4 zd~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lg za0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;Dajw zAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV z;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0 zgIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC z{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oadv*17U2`GR9|8EsYj)uj?LV8tSj*N_t zjOg9tLm_^xakX(Rq~9JtQBu(NdHT@E$3}(~Uud_lwJrbgvEx?W)wcfWJyjS#6dz89 z3S){}cFUiaXYjTCji+O2dMJJ37w(*xP<&D8i+az?%j07sW4F~`wH+A>`D6QrWyh_4 zSKIASA1goBC&r6Ix2KO4hHgtAFUI=j+YcQ-K3-IL?dLCr`seK(==brD-KL+_&)S>U zcjQRAw=dQ=&!6i%tOi^C71C0%Q!JS{F{I^6r&7-1>CF6D(NntV=Lw??_5~Cu;UvlLr;H) zim{K=(<&ZLjKKWGpj+lZ2i{CSI+pF z$D7T2KACN=uhcSo&EN75vAv;gYDhyzT>8bJ*6V)=Swfag{jJsQcGVs!6^d2-k8fJ| zldUtMKGV~Zq+VA&oA0ZHy|#{Z`&vuU*1qBopJ{ftEOeVK%fH{UBnz#O-fK1+jn+o1 z(P%cU4tZQ(H1-DD|EVg`4EuXOY-@Xq``gHlzP)WIf3O2)TS}$v_Ck`p-)yzdpI<+J zzTJxTQ@Jt3{rz?Gx#ym{eED)--rqEzeRgea?cBL@XU_as<%RZZ?+RJ{m9up%6k+un zr0=}adRXxTD`+FO(e!xuOt-t$SS%I0-M7E1cyDKCP-ClaY>#c!tS{wp6I8lRXK_{U zvVB#LaZA)+Z2t$6TZ1l?Y322{x3lir?3$j-l|x}UNkaY);()OH8&RwHsxQj3t**ZQ z=+H~lX+E5EH7zZ*wzpsXog}$s!essT%B3vp!V}xu>HwzSsO{*K;tEeZl%<=72kIbd z|5!MVnL<`S3lD|-Pn;^1t{pDF`EN?Ij=7NKSNTav^$R=Ee$sRy>AN&e+o^=XA&izvMK za`)EaQ1`9Bu!#1Y_t}^`N#2ROJM(!afAyd{nv({Cq&i^h35}(AAZ)sV1-JPt+Wgvssv&QB4MM;c5E$Fux05rRnnO zYN0qYNKclnLwE9csnjWrPSsm^yjhyDrdDb(-lUjDyL9g)p!jPuuaQs4YGLh z>1wsA@@!UN(Mn~dRPZWM-!Zy$HZ-&q5RIRpZ z+0_v3f6_XV&2N*Wu)12UDtq33+y9q_2m3D+m#hT}S$SqlL-jJftQw*A@%UNKUAV6n zI`5T!Y*3?+Nbt})Nx2mCq(4M5RdZvBV z%<*b0*!owtLC9Y=Q`#yP3x&A3X+1wbr&dJ0Eq}3iWh$F4Ee;iug;C9%u8xHbjJD;9 z9fIcdP=K;mCy$qgj!&$I_@+tOv6rBy-gAAk{-nOA;N4F zh~q=_pPijkI2ZeOXzJ>!<~@0TSdAgmRYPUfidP4SJ5X;3f`sGOu205qvsd|JSuy@~ z-#&(yXkUVL8<;p*M{8_&u@B|)-r%KNC>%RBJUl*r;>5~Ir_=9mZQZ)HySulyzkhJh z>zTdpbXHbQoERS;9zJ%gQ0Vu2y@P}O{k^^2-CMV|w&ah@%*-q=cRIg2pUzl|9(t%_ zVR?CG#yW(hTk;^T?CE^S9`kD+yR>OxDK{@+GHsJ;l@^2uw$Ud12AW30JPa8{P2mfL zmtHb7+uY11U@yI-O*-l+XU}$|>Z6L4%PXzYig0X0Lh)p!T8;m!kH-FJbJs9`4ac`s z8vCsa&%Chq%nQehHr}T+4r{BAOirptjat0^oA*EXYbSsEg<7pXYvuhPL)M(wn*V)S hA0{&2pa2S>01BW03ZMWApa2S>01BW03jC}o@ZS+Jp4R{X literal 0 HcmV?d00001 diff --git a/28_day/nihongo/jpn16v00.fnt b/28_day/nihongo/jpn16v00.fnt new file mode 100644 index 0000000000000000000000000000000000000000..cd7387ab0020c48601dfdd25c1d59d769fea5b44 GIT binary patch literal 58084 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 literal 0 HcmV?d00001 diff --git a/28_day/nihongo/nihongo.fnt b/28_day/nihongo/nihongo.fnt new file mode 100644 index 0000000000000000000000000000000000000000..e312bf5b7e4044adcff849980606951ba48bdd9a GIT binary patch literal 145472 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

GyQ$xxyMzR=Bd_b{buLbR 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 Date: Wed, 18 May 2016 12:58:00 +0800 Subject: [PATCH 51/83] =?UTF-8?q?=E6=97=A5=E6=96=87=E6=96=87=E5=AD=97?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=EF=BC=882=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 28_day/Makefile | 2 +- 28_day/haribote/bootpack.h | 2 +- 28_day/haribote/console.c | 6 +++ 28_day/haribote/graphic.c | 31 +++++++++-- 28_day/haribote/jp.nas | 107 +++++++++++++++++++++++++++++++++++++ 5 files changed, 143 insertions(+), 5 deletions(-) create mode 100644 28_day/haribote/jp.nas diff --git a/28_day/Makefile b/28_day/Makefile index ae13e61..191f468 100644 --- a/28_day/Makefile +++ b/28_day/Makefile @@ -25,7 +25,7 @@ haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:haribote/ipl10.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ - copy from:haribote/ipl10.nas to:@: \ + copy from:haribote/jp.nas to:@: \ copy from:make.bat to:@: \ copy from:a/a.hrb to:@: \ copy from:hello3/hello3.hrb to:@: \ diff --git a/28_day/haribote/bootpack.h b/28_day/haribote/bootpack.h index 3247663..f2e8243 100644 --- a/28_day/haribote/bootpack.h +++ b/28_day/haribote/bootpack.h @@ -217,7 +217,7 @@ struct TASK { struct FILEHANDLE *fhandle; int *fat; char *cmdline; - char langmode; + unsigned char langmode, langbyte1; }; struct TASKLEVEL { int running; /*正在运行的任务数量*/ diff --git a/28_day/haribote/console.c b/28_day/haribote/console.c index 7d6b750..e2e20f8 100644 --- a/28_day/haribote/console.c +++ b/28_day/haribote/console.c @@ -37,6 +37,7 @@ void console_task(struct SHEET *sheet, int memtotal) } else { task->langmode = 0; } + task->langbyte1 = 0; /*显示提示符*/ cons_putchar(&cons, '>', 1); @@ -158,6 +159,7 @@ void cons_newline(struct CONSOLE *cons) { int x, y; struct SHEET *sheet = cons->sht; + struct TASK *task = task_now(); if (cons->cur_y < 28 + 112) { cons->cur_y += 16; /*到下一行*/ } else { @@ -177,6 +179,9 @@ void cons_newline(struct CONSOLE *cons) } } cons->cur_x = 8; + if (task->langmode == 1 && task->langbyte1 != 0) { + cons->cur_x += 8; + } return; } @@ -403,6 +408,7 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) } timer_cancelall(&task->fifo); memman_free_4k(memman, (int) q, segsiz); + task->langbyte1 = 0; } else { cons_putstr0(cons, ".hrb file format error.\n"); } diff --git a/28_day/haribote/graphic.c b/28_day/haribote/graphic.c index 0df664b..ab39ac9 100644 --- a/28_day/haribote/graphic.c +++ b/28_day/haribote/graphic.c @@ -107,9 +107,10 @@ void putfont8(char *vram, int xsize, int x, int y, char c, char *font) void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s) { extern char hankaku[4096]; - /* C语言中,字符串都是以0x00结尾 */ struct TASK *task = task_now(); - char *nihongo = (char *) *((int *) 0x0fe8); + char *nihongo = (char *) *((int *) 0x0fe8), *font; + int k, t; + if (task->langmode == 0) { for (; *s != 0x00; s++) { putfont8(vram, xsize, x, y, c, hankaku + *s * 16); @@ -118,7 +119,31 @@ void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s } if (task->langmode == 1) { for (; *s != 0x00; s++) { - putfont8(vram, xsize, x, y, c, nihongo + *s * 16); + if (task->langbyte1 == 0) { + if ((0x81 <= *s && *s <= 0x9f) || (0xe0 <= *s && *s <= 0xfc)) { + task->langbyte1 = *s; + } else { + putfont8(vram, xsize, x, y, c, nihongo + *s * 16); + } + } else { + if (0x81 <= task->langbyte1 && task->langbyte1 <= 0x9f) { + k = (task->langbyte1 - 0x81) * 2; + } else { + k = (task->langbyte1 - 0xe0) * 2 + 62; + } + if (0x40 <= *s && *s <= 0x7e) { + t = *s - 0x40; + } else if (0x80 <= *s && *s <= 0x9e) { + t = *s - 0x80 + 63; + } else { + t = *s - 0x9f; + k++; + } + task->langbyte1 = 0; + font = nihongo + 256 * 16 + (k * 94 + t) * 32; + putfont8(vram, xsize, x - 8, y, c, font ); /* 左半部分 */ + putfont8(vram, xsize, x , y, c, font + 16); /* 右半部分 */ + } x += 8; } } diff --git a/28_day/haribote/jp.nas b/28_day/haribote/jp.nas new file mode 100644 index 0000000..3f7cb00 --- /dev/null +++ b/28_day/haribote/jp.nas @@ -0,0 +1,107 @@ +; haribote-ipl +; TAB=4 + +CYLS EQU 10 ; ǂ܂œǂݍނ + + ORG 0x7c00 ; ̃vOǂɓǂݍ܂̂ + +; ȉ͕WIFAT12tH[}bgtbs[fBXN̂߂̋Lq + + JMP entry + DB 0x90 + DB "HARIBOTE" ; u[gZN^̖ORɏĂ悢i8oCgj + DW 512 ; 1ZN^̑傫i512ɂȂ΂Ȃj + DB 1 ; NX^̑傫i1ZN^ɂȂ΂Ȃj + DW 1 ; FATǂn܂邩iʂ1ZN^ڂɂj + DB 2 ; FAŤi2ɂȂ΂Ȃj + DW 224 ; [gfBNg̈̑傫iʂ224Ggɂj + DW 2880 ; ̃hCȗ傫i2880ZN^ɂȂ΂Ȃj + DB 0xf0 ; fBÃ^Cvi0xf0ɂȂ΂Ȃj + DW 9 ; FAT̈̒i9ZN^ɂȂ΂Ȃj + DW 18 ; 1gbNɂ‚̃ZN^邩i18ɂȂ΂Ȃj + DW 2 ; wbh̐i2ɂȂ΂Ȃj + DD 0 ; p[eBVgĂȂ̂ł͕K0 + DD 2880 ; ̃hCu傫x + DB 0,0,0x29 ; 悭킩Ȃǂ̒lɂĂƂ炵 + DD 0xffffffff ; Ԃ{[VAԍ + DB "HARIBOTEOS " ; fBXN̖Oi11oCgj + DB "FAT12 " ; tH[}bg̖Oi8oCgj + RESB 18 ; Ƃ肠18oCgĂ + +; vO{ + +entry: + MOV AX,0 ; WX^ + MOV SS,AX + MOV SP,0x7c00 + MOV DS,AX + +; fBXNǂ + + MOV AX,0x0820 + MOV ES,AX + MOV CH,0 ; V_0 + MOV DH,0 ; wbh0 + MOV CL,2 ; ZN^2 +readloop: + MOV SI,0 ; s񐔂𐔂郌WX^ +retry: + MOV AH,0x02 ; AH=0x02 : fBXNǂݍ + MOV AL,1 ; 1ZN^ + MOV BX,0 + MOV DL,0x00 ; AhCu + INT 0x13 ; fBXNBIOSĂяo + JNC next ; G[Ȃnext + ADD SI,1 ; SI1𑫂 + CMP SI,5 ; SI5r + JAE error ; SI >= 5 error + MOV AH,0x00 + MOV DL,0x00 ; AhCu + INT 0x13 ; hCũZbg + JMP retry +next: + MOV AX,ES ; AhX0x200i߂ + ADD AX,0x0020 + MOV ES,AX ; ADD ES,0x020 Ƃ߂Ȃ̂łĂ + ADD CL,1 ; CL1𑫂 + CMP CL,18 ; CL18r + JBE readloop ; CL <= 18 readloop + MOV CL,1 + ADD DH,1 + CMP DH,2 + JB readloop ; DH < 2 readloop + MOV DH,0 + ADD CH,1 + CMP CH,CYLS + JB readloop ; CH < CYLS readloop + +; ǂݏÎharibote.syssI + + MOV [0x0ff0],CH ; IPLǂ܂œǂ񂾂̂ + JMP 0xc200 + +error: + MOV AX,0 + MOV ES,AX + MOV SI,msg +putloop: + MOV AL,[SI] + ADD SI,1 ; SI1𑫂 + CMP AL,0 + JE fin + MOV AH,0x0e ; ꕶ\t@NV + MOV BX,15 ; J[R[h + INT 0x10 ; rfIBIOSĂяo + JMP putloop +fin: + HLT ; ܂CPU~ + JMP fin ; [v +msg: + DB 0x0a, 0x0a ; s2 + DB "load error" + DB 0x0a ; s + DB 0 + + RESB 0x7dfe-$ ; 0x7dfe܂ł0x00Ŗ߂閽 + + DB 0x55, 0xaa From 7497159026b52b78bbaaf1570b1c0db0fd520c07 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 18 May 2016 13:08:09 +0800 Subject: [PATCH 52/83] =?UTF-8?q?=E6=97=A5=E6=96=87=E6=96=87=E5=AD=97?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=EF=BC=883=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 28_day/Makefile | 12 +++- 28_day/apilib.h | 1 + 28_day/apilib/Makefile | 2 +- 28_day/apilib/api027.nas | 13 +++++ 28_day/chklang/!cons_9x.bat | 1 + 28_day/chklang/!cons_nt.bat | 1 + 28_day/chklang/Makefile | 5 ++ 28_day/chklang/chklang.c | 24 ++++++++ 28_day/chklang/make.bat | 1 + 28_day/euc.txt | 1 + 28_day/haribote/Makefile | 6 +- 28_day/haribote/console.c | 4 +- 28_day/haribote/graphic.c | 19 +++++++ 28_day/haribote/ipl20.nas | 109 ++++++++++++++++++++++++++++++++++++ 14 files changed, 193 insertions(+), 6 deletions(-) create mode 100644 28_day/apilib/api027.nas create mode 100644 28_day/chklang/!cons_9x.bat create mode 100644 28_day/chklang/!cons_nt.bat create mode 100644 28_day/chklang/Makefile create mode 100644 28_day/chklang/chklang.c create mode 100644 28_day/chklang/make.bat create mode 100644 28_day/euc.txt create mode 100644 28_day/haribote/ipl20.nas diff --git a/28_day/Makefile b/28_day/Makefile index 191f468..5e59a38 100644 --- a/28_day/Makefile +++ b/28_day/Makefile @@ -14,16 +14,17 @@ default : #文件生成规则 -haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ +haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ a/a.hrb hello3/hello3.hrb hello4/hello4.hrb hello5/hello5.hrb \ winhelo/winhelo.hrb winhelo2/winhelo2.hrb winhelo3/winhelo3.hrb \ star1/star1.hrb stars/stars.hrb stars2/stars2.hrb \ lines/lines.hrb walk/walk.hrb noodle/noodle.hrb \ beepdown/beepdown.hrb color/color.hrb color2/color2.hrb \ sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb \ - typeipl/typeipl.hrb type/type.hrb iroha/iroha.hrb + typeipl/typeipl.hrb type/type.hrb iroha/iroha.hrb \ + chklang/chklang.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ - wbinimg src:haribote/ipl10.bin len:512 from:0 to:0 \ + wbinimg src:haribote/ipl20.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ copy from:haribote/jp.nas to:@: \ copy from:make.bat to:@: \ @@ -49,6 +50,8 @@ haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ copy from:typeipl/typeipl.hrb to:@: \ copy from:type/type.hrb to:@: \ copy from:iroha/iroha.hrb to:@: \ + copy from:chklang/chklang.hrb to:@: \ + copy from:euc.txt to:@: \ copy from:nihongo/nihongo.fnt to:@: \ imgout:haribote.img @@ -88,6 +91,7 @@ full : $(MAKE) -C typeipl $(MAKE) -C type $(MAKE) -C iroha + $(MAKE) -C chklang $(MAKE) haribote.img run_full : @@ -135,6 +139,7 @@ clean_full : $(MAKE) -C typeipl clean $(MAKE) -C type clean $(MAKE) -C iroha clean + $(MAKE) -C chklang clean src_only_full : $(MAKE) -C haribote src_only @@ -161,6 +166,7 @@ src_only_full : $(MAKE) -C typeipl src_only $(MAKE) -C type src_only $(MAKE) -C iroha src_only + $(MAKE) -C chklang src_only -$(DEL) haribote.img refresh : diff --git a/28_day/apilib.h b/28_day/apilib.h index fbf0884..ac282d8 100644 --- a/28_day/apilib.h +++ b/28_day/apilib.h @@ -24,3 +24,4 @@ void api_fseek(int fhandle, int offset, int mode); int api_fsize(int fhandle, int mode); int api_fread(char *buf, int maxsize, int fhandle); int api_cmdline(char *buf, int maxsize); +int api_getlang(void); diff --git a/28_day/apilib/Makefile b/28_day/apilib/Makefile index b40633b..8ce9ef5 100644 --- a/28_day/apilib/Makefile +++ b/28_day/apilib/Makefile @@ -2,7 +2,7 @@ OBJS_API = api001.obj api002.obj api003.obj api004.obj api005.obj api006.obj \ api007.obj api008.obj api009.obj api010.obj api011.obj api012.obj \ api013.obj api014.obj api015.obj api016.obj api017.obj api018.obj \ api019.obj api020.obj api021.obj api022.obj api023.obj api024.obj \ - api025.obj api026.obj alloca.obj + api025.obj api026.obj api027.obj alloca.obj TOOLPATH = ../../z_tools/ INCPATH = ../../z_tools/haribote/ diff --git a/28_day/apilib/api027.nas b/28_day/apilib/api027.nas new file mode 100644 index 0000000..38bfbc1 --- /dev/null +++ b/28_day/apilib/api027.nas @@ -0,0 +1,13 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api027.nas"] + + GLOBAL _api_getlang + +[SECTION .text] + +_api_getlang: ; int api_getlang(void); + MOV EDX,27 + INT 0x40 + RET diff --git a/28_day/chklang/!cons_9x.bat b/28_day/chklang/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/28_day/chklang/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/28_day/chklang/!cons_nt.bat b/28_day/chklang/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/28_day/chklang/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/28_day/chklang/Makefile b/28_day/chklang/Makefile new file mode 100644 index 0000000..c00ebbc --- /dev/null +++ b/28_day/chklang/Makefile @@ -0,0 +1,5 @@ +APP = chklang +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/28_day/chklang/chklang.c b/28_day/chklang/chklang.c new file mode 100644 index 0000000..3c28491 --- /dev/null +++ b/28_day/chklang/chklang.c @@ -0,0 +1,24 @@ +#include "apilib.h" + +void HariMain(void) +{ + int langmode = api_getlang(); + static char s1[23] = { /* 日本語シフトJISモード(日文Shift-JIS模式)*/ + 0x93, 0xfa, 0x96, 0x7b, 0x8c, 0xea, 0x83, 0x56, 0x83, 0x74, 0x83, 0x67, + 0x4a, 0x49, 0x53, 0x83, 0x82, 0x81, 0x5b, 0x83, 0x68, 0x0a, 0x00 + }; + static char s2[17] = { /*日本語EUCモード(日文EUC模式)*/ + 0xc6, 0xfc, 0xcb, 0xdc, 0xb8, 0xec, 0x45, 0x55, 0x43, 0xa5, 0xe2, 0xa1, + 0xbc, 0xa5, 0xc9, 0x0a, 0x00 + }; + if (langmode == 0) { + api_putstr0("English ASCII mode\n"); + } + if (langmode == 1) { + api_putstr0(s1); + } + if (langmode == 2) { + api_putstr0(s2); + } + api_end(); +} diff --git a/28_day/chklang/make.bat b/28_day/chklang/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/28_day/chklang/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/28_day/euc.txt b/28_day/euc.txt new file mode 100644 index 0000000..ae6d81a --- /dev/null +++ b/28_day/euc.txt @@ -0,0 +1 @@ +ܸEUCǽ񤤤Ƥߤ衼 diff --git a/28_day/haribote/Makefile b/28_day/haribote/Makefile index b0ce461..374bba7 100644 --- a/28_day/haribote/Makefile +++ b/28_day/haribote/Makefile @@ -23,7 +23,7 @@ DEL = del #默认动作 default : - $(MAKE) ipl10.bin + $(MAKE) ipl20.bin $(MAKE) haribote.sys # 镜像文件生成 @@ -31,6 +31,9 @@ default : ipl10.bin : ipl10.nas Makefile $(NASK) ipl10.nas ipl10.bin ipl10.lst +ipl20.bin : ipl20.nas Makefile + $(NASK) ipl20.nas ipl20.bin ipl20.lst + asmhead.bin : asmhead.nas Makefile $(NASK) asmhead.nas asmhead.bin asmhead.lst @@ -76,4 +79,5 @@ clean : src_only : $(MAKE) clean -$(DEL) ipl10.bin + -$(DEL) ipl20.bin -$(DEL) haribote.sys diff --git a/28_day/haribote/console.c b/28_day/haribote/console.c index e2e20f8..b231d2b 100644 --- a/28_day/haribote/console.c +++ b/28_day/haribote/console.c @@ -334,7 +334,7 @@ void cmd_langmode(struct CONSOLE *cons, char *cmdline) { struct TASK *task = task_now(); unsigned char mode = cmdline[9] - '0'; - if (mode <= 1) { + if (mode <= 2) { task->langmode = mode; } else { cons_putstr0(cons, "mode number error.\n"); @@ -620,6 +620,8 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int i++; } reg[7] = i; + } else if (edx == 27) { + reg[7] = task->langmode; } return 0; } diff --git a/28_day/haribote/graphic.c b/28_day/haribote/graphic.c index ab39ac9..3ac5000 100644 --- a/28_day/haribote/graphic.c +++ b/28_day/haribote/graphic.c @@ -147,6 +147,25 @@ void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s x += 8; } } + if (task->langmode == 2) { + for (; *s != 0x00; s++) { + if (task->langbyte1 == 0) { + if (0x81 <= *s && *s <= 0xfe) { + task->langbyte1 = *s; + } else { + putfont8(vram, xsize, x, y, c, nihongo + *s * 16); + } + } else { + k = task->langbyte1 - 0xa1; + t = *s - 0xa1; + task->langbyte1 = 0; + font = nihongo + 256 * 16 + (k * 94 + t) * 32; + putfont8(vram, xsize, x - 8, y, c, font ); /* 左半部分 */ + putfont8(vram, xsize, x , y, c, font + 16); /* 右半部分 */ + } + x += 8; + } + } return; } diff --git a/28_day/haribote/ipl20.nas b/28_day/haribote/ipl20.nas new file mode 100644 index 0000000..9b14835 --- /dev/null +++ b/28_day/haribote/ipl20.nas @@ -0,0 +1,109 @@ +; haribote-ipl +; TAB=4 + +CYLS EQU 20 ; 声明CYLS=20 + + ORG 0x7c00 ; 指明程序装载地址 + +; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code + + JMP entry + DB 0x90 + DB "HARIBOTE" ; 启动扇区名称(8字节) + DW 512 ; 每个扇区(sector)大小(必须512字节) + DB 1 ; 簇(cluster)大小(必须为1个扇区) + DW 1 ; FAT起始位置(一般为第一个扇区) + DB 2 ; FAT个数(必须为2) + DW 224 ; 根目录大小(一般为224项) + DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512) + DB 0xf0 ; 磁盘类型(必须为0xf0) + DW 9 ; FAT的长度(必??9扇区) + DW 18 ; 一个磁道(track)有几个扇区(必须为18) + DW 2 ; 磁头数(必??2) + DD 0 ; 不使用分区,必须是0 + DD 2880 ; 重写一次磁盘大小 + DB 0,0,0x29 ; 意义不明(固定) + DD 0xffffffff ; (可能是)卷标号码 + DB "HARIBOTEOS " ; 磁盘的名称(必须为11字?,不足填空格) + DB "FAT12 " ; 磁盘格式名称(必??8字?,不足填空格) + RESB 18 ; 先空出18字节 + +; 程序主体 + +entry: + MOV AX,0 ; 初始化寄存器 + MOV SS,AX + MOV SP,0x7c00 + MOV DS,AX + +; 读取磁盘 + + MOV AX,0x0820 + MOV ES,AX + MOV CH,0 ; 柱面0 + MOV DH,0 ; 磁头0 + MOV CL,2 ; 扇区2 + +readloop: + MOV SI,0 ; 记录失败次数寄存器 + +retry: + MOV AH,0x02 ; AH=0x02 : 读入磁盘 + MOV AL,1 ; 1个扇区 + MOV BX,0 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 调用磁盘BIOS + JNC next ; 没出错则跳转到fin + ADD SI,1 ; 往SI加1 + CMP SI,5 ; 比较SI与5 + JAE error ; SI >= 5 跳转到error + MOV AH,0x00 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 重置驱动器 + JMP retry +next: + MOV AX,ES ; 把内存地址后移0x200(512/16十六进制转换) + ADD AX,0x0020 + MOV ES,AX ; ADD ES,0x020因为没有ADD ES,只能通过AX进行 + ADD CL,1 ; 往CL里面加1 + CMP CL,18 ; 比较CL与18 + JBE readloop ; CL <= 18 跳转到readloop + MOV CL,1 + ADD DH,1 + CMP DH,2 + JB readloop ; DH < 2 跳转到readloop + MOV DH,0 + ADD CH,1 + CMP CH,CYLS + JB readloop ; CH < CYLS 跳转到readloop + +; 读取完毕,跳转到haribote.sys执行! + MOV [0x0ff0],CH ; IPLがどこまで読んだのかをメモ + JMP 0xc200 + +error: + MOV SI,msg + +putloop: + MOV AL,[SI] + ADD SI,1 ; 给SI加1 + CMP AL,0 + JE fin + MOV AH,0x0e ; 显示一个文字 + MOV BX,15 ; 指定字符颜色 + INT 0x10 ; 调用显卡BIOS + JMP putloop + +fin: + HLT ; 让CPU停止,等待指令 + JMP fin ; 无限循环 + +msg: + DB 0x0a, 0x0a ; 换行两次 + DB "load error" + DB 0x0a ; 换行 + DB 0 + + RESB 0x7dfe-$ ; 填写0x00直到0x001fe + + DB 0x55, 0xaa From d925a8d99230ef362650e56d31c3f58b39514afb Mon Sep 17 00:00:00 2001 From: Yourtion Date: Wed, 18 May 2016 13:20:49 +0800 Subject: [PATCH 53/83] update --- 27_day/haribote/ipl10.bin | Bin 512 -> 0 bytes 28_day/Makefile | 72 +++++++++++++++++++------------------- 28_day/haribote/ipl10.bin | Bin 512 -> 0 bytes 3 files changed, 36 insertions(+), 36 deletions(-) delete mode 100644 27_day/haribote/ipl10.bin delete mode 100644 28_day/haribote/ipl10.bin diff --git a/27_day/haribote/ipl10.bin b/27_day/haribote/ipl10.bin deleted file mode 100644 index 9ac675e6579d9ff288934f5c4a7cbf633f1e7076..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 512 zcmaFuH^IX($kWL`#Fc@Gk&%Jv0fPhg2Tled1||j&aNq`!n*V_Srp`ZD!Obzm&`3c+ z0VIbCb}%sXUD(4=(|2Qs0!QD0tqj{3HZtvFVA#U6fpIqj!zPBa!o>p3#~7Rcu@)O` z0rOu!?m57!z|eP~;UHtfPoc7l8yOppF*f{TDmuQ6q2VZF!(XnVy&ZZV_+JLPf{Z_~ y?@Ub>3(yQ3h7!&#e7pG>&I-JK_vQ6pF0P#X#1w_pqN4mFE>vfY^00p3#~7Rcu@)O` z0rOu!?m57!z|eP~;UHtfPoc7l8yOppF*f{TDmuQ6q2VZF!(XnVy&ZZV_+JLPf{Z_~ y?@Ub>3(yQ3h7!&#e7pG>&I-JK_vQ6pF0P#X#1w_pqN4mFE>vfY^00 Date: Thu, 19 May 2016 12:27:14 +0800 Subject: [PATCH 54/83] Add 29 day code --- 29_day/!cons_9x.bat | 1 + 29_day/!cons_nt.bat | 1 + 29_day/Makefile | 175 ++ 29_day/a/!cons_9x.bat | 1 + 29_day/a/!cons_nt.bat | 1 + 29_day/a/Makefile | 5 + 29_day/a/a.c | 7 + 29_day/a/make.bat | 1 + 29_day/apilib.h | 27 + 29_day/apilib/!cons_9x.bat | 1 + 29_day/apilib/!cons_nt.bat | 1 + 29_day/apilib/Makefile | 48 + 29_day/apilib/alloca.nas | 13 + 29_day/apilib/api001.nas | 14 + 29_day/apilib/api002.nas | 16 + 29_day/apilib/api003.nas | 17 + 29_day/apilib/api004.nas | 12 + 29_day/apilib/api005.nas | 24 + 29_day/apilib/api006.nas | 27 + 29_day/apilib/api007.nas | 27 + 29_day/apilib/api008.nas | 20 + 29_day/apilib/api009.nas | 17 + 29_day/apilib/api010.nas | 18 + 29_day/apilib/api011.nas | 23 + 29_day/apilib/api012.nas | 24 + 29_day/apilib/api013.nas | 27 + 29_day/apilib/api014.nas | 16 + 29_day/apilib/api015.nas | 14 + 29_day/apilib/api016.nas | 13 + 29_day/apilib/api017.nas | 17 + 29_day/apilib/api018.nas | 17 + 29_day/apilib/api019.nas | 16 + 29_day/apilib/api020.nas | 14 + 29_day/apilib/api021.nas | 16 + 29_day/apilib/api022.nas | 14 + 29_day/apilib/api023.nas | 18 + 29_day/apilib/api024.nas | 15 + 29_day/apilib/api025.nas | 18 + 29_day/apilib/api026.nas | 17 + 29_day/apilib/api027.nas | 13 + 29_day/apilib/apilib.lib | Bin 0 -> 8966 bytes 29_day/apilib/make.bat | 1 + 29_day/app_make.txt | 79 + 29_day/beepdown/!cons_9x.bat | 1 + 29_day/beepdown/!cons_nt.bat | 1 + 29_day/beepdown/Makefile | 5 + 29_day/beepdown/beepdown.c | 19 + 29_day/beepdown/make.bat | 1 + 29_day/chklang/!cons_9x.bat | 1 + 29_day/chklang/!cons_nt.bat | 1 + 29_day/chklang/Makefile | 5 + 29_day/chklang/chklang.c | 24 + 29_day/chklang/make.bat | 1 + 29_day/color/!cons_9x.bat | 1 + 29_day/color/!cons_nt.bat | 1 + 29_day/color/Makefile | 5 + 29_day/color/color.c | 21 + 29_day/color/make.bat | 1 + 29_day/color2/!cons_9x.bat | 1 + 29_day/color2/!cons_nt.bat | 1 + 29_day/color2/Makefile | 5 + 29_day/color2/color2.c | 36 + 29_day/color2/make.bat | 1 + 29_day/euc.txt | 1 + 29_day/haribote.rul | 10 + 29_day/haribote/!cons_9x.bat | 1 + 29_day/haribote/!cons_nt.bat | 1 + 29_day/haribote/Makefile | 83 + 29_day/haribote/asmhead.nas | 202 ++ 29_day/haribote/bootpack.c | 410 +++ 29_day/haribote/bootpack.h | 292 +++ 29_day/haribote/console.c | 698 +++++ 29_day/haribote/dsctbl.c | 59 + 29_day/haribote/fifo.c | 63 + 29_day/haribote/file.c | 74 + 29_day/haribote/graphic.c | 221 ++ 29_day/haribote/hankaku.txt | 4609 ++++++++++++++++++++++++++++++++++ 29_day/haribote/haribote.sys | Bin 0 -> 33331 bytes 29_day/haribote/int.c | 26 + 29_day/haribote/ipl10.nas | 109 + 29_day/haribote/ipl20.nas | 109 + 29_day/haribote/jp.nas | 107 + 29_day/haribote/keyboard.c | 44 + 29_day/haribote/make.bat | 1 + 29_day/haribote/memory.c | 162 ++ 29_day/haribote/mouse.c | 76 + 29_day/haribote/mtask.c | 203 ++ 29_day/haribote/naskfunc.nas | 291 +++ 29_day/haribote/sheet.c | 294 +++ 29_day/haribote/timer.c | 169 ++ 29_day/haribote/window.c | 118 + 29_day/hello3/!cons_9x.bat | 1 + 29_day/hello3/!cons_nt.bat | 1 + 29_day/hello3/Makefile | 5 + 29_day/hello3/hello3.c | 11 + 29_day/hello3/make.bat | 1 + 29_day/hello4/!cons_9x.bat | 1 + 29_day/hello4/!cons_nt.bat | 1 + 29_day/hello4/Makefile | 5 + 29_day/hello4/hello4.c | 7 + 29_day/hello4/make.bat | 1 + 29_day/hello5/!cons_9x.bat | 1 + 29_day/hello5/!cons_nt.bat | 1 + 29_day/hello5/Makefile | 5 + 29_day/hello5/hello5.nas | 20 + 29_day/hello5/make.bat | 1 + 29_day/iroha/!cons_9x.bat | 1 + 29_day/iroha/!cons_nt.bat | 1 + 29_day/iroha/Makefile | 5 + 29_day/iroha/iroha.c | 9 + 29_day/iroha/make.bat | 1 + 29_day/lines/!cons_9x.bat | 1 + 29_day/lines/!cons_nt.bat | 1 + 29_day/lines/Makefile | 5 + 29_day/lines/lines.c | 22 + 29_day/lines/make.bat | 1 + 29_day/make.bat | 1 + 29_day/nihongo/jpn16v00.bin | Bin 0 -> 311296 bytes 29_day/nihongo/jpn16v00.fnt | Bin 0 -> 58084 bytes 29_day/nihongo/nihongo.fnt | Bin 0 -> 145472 bytes 29_day/noodle/!cons_9x.bat | 1 + 29_day/noodle/!cons_nt.bat | 1 + 29_day/noodle/Makefile | 5 + 29_day/noodle/make.bat | 1 + 29_day/noodle/noodle.c | 32 + 29_day/sosu/!cons_9x.bat | 1 + 29_day/sosu/!cons_nt.bat | 1 + 29_day/sosu/Makefile | 5 + 29_day/sosu/make.bat | 1 + 29_day/sosu/sosu.c | 24 + 29_day/sosu2/!cons_9x.bat | 1 + 29_day/sosu2/!cons_nt.bat | 1 + 29_day/sosu2/Makefile | 5 + 29_day/sosu2/make.bat | 1 + 29_day/sosu2/sosu2.c | 24 + 29_day/sosu3/!cons_9x.bat | 1 + 29_day/sosu3/!cons_nt.bat | 1 + 29_day/sosu3/Makefile | 5 + 29_day/sosu3/make.bat | 1 + 29_day/sosu3/sosu3.c | 26 + 29_day/star1/!cons_9x.bat | 1 + 29_day/star1/!cons_nt.bat | 1 + 29_day/star1/Makefile | 5 + 29_day/star1/make.bat | 1 + 29_day/star1/star1.c | 18 + 29_day/stars/!cons_9x.bat | 1 + 29_day/stars/!cons_nt.bat | 1 + 29_day/stars/Makefile | 5 + 29_day/stars/make.bat | 1 + 29_day/stars/stars.c | 24 + 29_day/stars2/!cons_9x.bat | 1 + 29_day/stars2/!cons_nt.bat | 1 + 29_day/stars2/Makefile | 5 + 29_day/stars2/make.bat | 1 + 29_day/stars2/stars2.c | 25 + 29_day/type/!cons_9x.bat | 1 + 29_day/type/!cons_nt.bat | 1 + 29_day/type/Makefile | 5 + 29_day/type/make.bat | 1 + 29_day/type/type.c | 23 + 29_day/typeipl/!cons_9x.bat | 1 + 29_day/typeipl/!cons_nt.bat | 1 + 29_day/typeipl/Makefile | 5 + 29_day/typeipl/make.bat | 1 + 29_day/typeipl/typeipl.c | 17 + 29_day/walk/!cons_9x.bat | 1 + 29_day/walk/!cons_nt.bat | 1 + 29_day/walk/Makefile | 5 + 29_day/walk/make.bat | 1 + 29_day/walk/walk.c | 26 + 29_day/winhelo/!cons_9x.bat | 1 + 29_day/winhelo/!cons_nt.bat | 1 + 29_day/winhelo/Makefile | 5 + 29_day/winhelo/make.bat | 1 + 29_day/winhelo/winhelo.c | 15 + 29_day/winhelo2/!cons_9x.bat | 1 + 29_day/winhelo2/!cons_nt.bat | 1 + 29_day/winhelo2/Makefile | 5 + 29_day/winhelo2/make.bat | 1 + 29_day/winhelo2/winhelo2.c | 17 + 29_day/winhelo3/!cons_9x.bat | 1 + 29_day/winhelo3/!cons_nt.bat | 1 + 29_day/winhelo3/Makefile | 5 + 29_day/winhelo3/make.bat | 1 + 29_day/winhelo3/winhelo3.c | 19 + 185 files changed, 9915 insertions(+) create mode 100644 29_day/!cons_9x.bat create mode 100644 29_day/!cons_nt.bat create mode 100644 29_day/Makefile create mode 100644 29_day/a/!cons_9x.bat create mode 100644 29_day/a/!cons_nt.bat create mode 100644 29_day/a/Makefile create mode 100644 29_day/a/a.c create mode 100644 29_day/a/make.bat create mode 100644 29_day/apilib.h create mode 100644 29_day/apilib/!cons_9x.bat create mode 100644 29_day/apilib/!cons_nt.bat create mode 100644 29_day/apilib/Makefile create mode 100644 29_day/apilib/alloca.nas create mode 100644 29_day/apilib/api001.nas create mode 100644 29_day/apilib/api002.nas create mode 100644 29_day/apilib/api003.nas create mode 100644 29_day/apilib/api004.nas create mode 100644 29_day/apilib/api005.nas create mode 100644 29_day/apilib/api006.nas create mode 100644 29_day/apilib/api007.nas create mode 100644 29_day/apilib/api008.nas create mode 100644 29_day/apilib/api009.nas create mode 100644 29_day/apilib/api010.nas create mode 100644 29_day/apilib/api011.nas create mode 100644 29_day/apilib/api012.nas create mode 100644 29_day/apilib/api013.nas create mode 100644 29_day/apilib/api014.nas create mode 100644 29_day/apilib/api015.nas create mode 100644 29_day/apilib/api016.nas create mode 100644 29_day/apilib/api017.nas create mode 100644 29_day/apilib/api018.nas create mode 100644 29_day/apilib/api019.nas create mode 100644 29_day/apilib/api020.nas create mode 100644 29_day/apilib/api021.nas create mode 100644 29_day/apilib/api022.nas create mode 100644 29_day/apilib/api023.nas create mode 100644 29_day/apilib/api024.nas create mode 100644 29_day/apilib/api025.nas create mode 100644 29_day/apilib/api026.nas create mode 100644 29_day/apilib/api027.nas create mode 100644 29_day/apilib/apilib.lib create mode 100644 29_day/apilib/make.bat create mode 100644 29_day/app_make.txt create mode 100644 29_day/beepdown/!cons_9x.bat create mode 100644 29_day/beepdown/!cons_nt.bat create mode 100644 29_day/beepdown/Makefile create mode 100644 29_day/beepdown/beepdown.c create mode 100644 29_day/beepdown/make.bat create mode 100644 29_day/chklang/!cons_9x.bat create mode 100644 29_day/chklang/!cons_nt.bat create mode 100644 29_day/chklang/Makefile create mode 100644 29_day/chklang/chklang.c create mode 100644 29_day/chklang/make.bat create mode 100644 29_day/color/!cons_9x.bat create mode 100644 29_day/color/!cons_nt.bat create mode 100644 29_day/color/Makefile create mode 100644 29_day/color/color.c create mode 100644 29_day/color/make.bat create mode 100644 29_day/color2/!cons_9x.bat create mode 100644 29_day/color2/!cons_nt.bat create mode 100644 29_day/color2/Makefile create mode 100644 29_day/color2/color2.c create mode 100644 29_day/color2/make.bat create mode 100644 29_day/euc.txt create mode 100644 29_day/haribote.rul create mode 100644 29_day/haribote/!cons_9x.bat create mode 100644 29_day/haribote/!cons_nt.bat create mode 100644 29_day/haribote/Makefile create mode 100644 29_day/haribote/asmhead.nas create mode 100644 29_day/haribote/bootpack.c create mode 100644 29_day/haribote/bootpack.h create mode 100644 29_day/haribote/console.c create mode 100644 29_day/haribote/dsctbl.c create mode 100644 29_day/haribote/fifo.c create mode 100644 29_day/haribote/file.c create mode 100644 29_day/haribote/graphic.c create mode 100644 29_day/haribote/hankaku.txt create mode 100644 29_day/haribote/haribote.sys create mode 100644 29_day/haribote/int.c create mode 100644 29_day/haribote/ipl10.nas create mode 100644 29_day/haribote/ipl20.nas create mode 100644 29_day/haribote/jp.nas create mode 100644 29_day/haribote/keyboard.c create mode 100644 29_day/haribote/make.bat create mode 100644 29_day/haribote/memory.c create mode 100644 29_day/haribote/mouse.c create mode 100644 29_day/haribote/mtask.c create mode 100644 29_day/haribote/naskfunc.nas create mode 100644 29_day/haribote/sheet.c create mode 100644 29_day/haribote/timer.c create mode 100644 29_day/haribote/window.c create mode 100644 29_day/hello3/!cons_9x.bat create mode 100644 29_day/hello3/!cons_nt.bat create mode 100644 29_day/hello3/Makefile create mode 100644 29_day/hello3/hello3.c create mode 100644 29_day/hello3/make.bat create mode 100644 29_day/hello4/!cons_9x.bat create mode 100644 29_day/hello4/!cons_nt.bat create mode 100644 29_day/hello4/Makefile create mode 100644 29_day/hello4/hello4.c create mode 100644 29_day/hello4/make.bat create mode 100644 29_day/hello5/!cons_9x.bat create mode 100644 29_day/hello5/!cons_nt.bat create mode 100644 29_day/hello5/Makefile create mode 100644 29_day/hello5/hello5.nas create mode 100644 29_day/hello5/make.bat create mode 100644 29_day/iroha/!cons_9x.bat create mode 100644 29_day/iroha/!cons_nt.bat create mode 100644 29_day/iroha/Makefile create mode 100644 29_day/iroha/iroha.c create mode 100644 29_day/iroha/make.bat create mode 100644 29_day/lines/!cons_9x.bat create mode 100644 29_day/lines/!cons_nt.bat create mode 100644 29_day/lines/Makefile create mode 100644 29_day/lines/lines.c create mode 100644 29_day/lines/make.bat create mode 100644 29_day/make.bat create mode 100644 29_day/nihongo/jpn16v00.bin create mode 100644 29_day/nihongo/jpn16v00.fnt create mode 100644 29_day/nihongo/nihongo.fnt create mode 100644 29_day/noodle/!cons_9x.bat create mode 100644 29_day/noodle/!cons_nt.bat create mode 100644 29_day/noodle/Makefile create mode 100644 29_day/noodle/make.bat create mode 100644 29_day/noodle/noodle.c create mode 100644 29_day/sosu/!cons_9x.bat create mode 100644 29_day/sosu/!cons_nt.bat create mode 100644 29_day/sosu/Makefile create mode 100644 29_day/sosu/make.bat create mode 100644 29_day/sosu/sosu.c create mode 100644 29_day/sosu2/!cons_9x.bat create mode 100644 29_day/sosu2/!cons_nt.bat create mode 100644 29_day/sosu2/Makefile create mode 100644 29_day/sosu2/make.bat create mode 100644 29_day/sosu2/sosu2.c create mode 100644 29_day/sosu3/!cons_9x.bat create mode 100644 29_day/sosu3/!cons_nt.bat create mode 100644 29_day/sosu3/Makefile create mode 100644 29_day/sosu3/make.bat create mode 100644 29_day/sosu3/sosu3.c create mode 100644 29_day/star1/!cons_9x.bat create mode 100644 29_day/star1/!cons_nt.bat create mode 100644 29_day/star1/Makefile create mode 100644 29_day/star1/make.bat create mode 100644 29_day/star1/star1.c create mode 100644 29_day/stars/!cons_9x.bat create mode 100644 29_day/stars/!cons_nt.bat create mode 100644 29_day/stars/Makefile create mode 100644 29_day/stars/make.bat create mode 100644 29_day/stars/stars.c create mode 100644 29_day/stars2/!cons_9x.bat create mode 100644 29_day/stars2/!cons_nt.bat create mode 100644 29_day/stars2/Makefile create mode 100644 29_day/stars2/make.bat create mode 100644 29_day/stars2/stars2.c create mode 100644 29_day/type/!cons_9x.bat create mode 100644 29_day/type/!cons_nt.bat create mode 100644 29_day/type/Makefile create mode 100644 29_day/type/make.bat create mode 100644 29_day/type/type.c create mode 100644 29_day/typeipl/!cons_9x.bat create mode 100644 29_day/typeipl/!cons_nt.bat create mode 100644 29_day/typeipl/Makefile create mode 100644 29_day/typeipl/make.bat create mode 100644 29_day/typeipl/typeipl.c create mode 100644 29_day/walk/!cons_9x.bat create mode 100644 29_day/walk/!cons_nt.bat create mode 100644 29_day/walk/Makefile create mode 100644 29_day/walk/make.bat create mode 100644 29_day/walk/walk.c create mode 100644 29_day/winhelo/!cons_9x.bat create mode 100644 29_day/winhelo/!cons_nt.bat create mode 100644 29_day/winhelo/Makefile create mode 100644 29_day/winhelo/make.bat create mode 100644 29_day/winhelo/winhelo.c create mode 100644 29_day/winhelo2/!cons_9x.bat create mode 100644 29_day/winhelo2/!cons_nt.bat create mode 100644 29_day/winhelo2/Makefile create mode 100644 29_day/winhelo2/make.bat create mode 100644 29_day/winhelo2/winhelo2.c create mode 100644 29_day/winhelo3/!cons_9x.bat create mode 100644 29_day/winhelo3/!cons_nt.bat create mode 100644 29_day/winhelo3/Makefile create mode 100644 29_day/winhelo3/make.bat create mode 100644 29_day/winhelo3/winhelo3.c diff --git a/29_day/!cons_9x.bat b/29_day/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/!cons_nt.bat b/29_day/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/Makefile b/29_day/Makefile new file mode 100644 index 0000000..e6b82cf --- /dev/null +++ b/29_day/Makefile @@ -0,0 +1,175 @@ +TOOLPATH = ../z_tools/ +INCPATH = ../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) haribote.img + +#文件生成规则 + +haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ + a/a.hrb hello3/hello3.hrb hello4/hello4.hrb hello5/hello5.hrb \ + winhelo/winhelo.hrb winhelo2/winhelo2.hrb winhelo3/winhelo3.hrb \ + star1/star1.hrb stars/stars.hrb stars2/stars2.hrb \ + lines/lines.hrb walk/walk.hrb noodle/noodle.hrb \ + beepdown/beepdown.hrb color/color.hrb color2/color2.hrb \ + sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb \ + typeipl/typeipl.hrb type/type.hrb iroha/iroha.hrb \ + chklang/chklang.hrb + $(EDIMG) imgin:../z_tools/fdimg0at.tek \ + wbinimg src:haribote/ipl20.bin len:512 from:0 to:0 \ + copy from:haribote/haribote.sys to:@: \ + copy from:haribote/jp.nas to:@: \ + copy from:make.bat to:@: \ + copy from:a/a.hrb to:@: \ + copy from:hello3/hello3.hrb to:@: \ + copy from:hello4/hello4.hrb to:@: \ + copy from:hello5/hello5.hrb to:@: \ + copy from:winhelo/winhelo.hrb to:@: \ + copy from:winhelo2/winhelo2.hrb to:@: \ + copy from:winhelo3/winhelo3.hrb to:@: \ + copy from:star1/star1.hrb to:@: \ + copy from:stars/stars.hrb to:@: \ + copy from:stars2/stars2.hrb to:@: \ + copy from:lines/lines.hrb to:@: \ + copy from:walk/walk.hrb to:@: \ + copy from:noodle/noodle.hrb to:@: \ + copy from:beepdown/beepdown.hrb to:@: \ + copy from:color/color.hrb to:@: \ + copy from:color2/color2.hrb to:@: \ + copy from:sosu/sosu.hrb to:@: \ + copy from:sosu2/sosu2.hrb to:@: \ + copy from:sosu3/sosu3.hrb to:@: \ + copy from:typeipl/typeipl.hrb to:@: \ + copy from:type/type.hrb to:@: \ + copy from:iroha/iroha.hrb to:@: \ + copy from:chklang/chklang.hrb to:@: \ + copy from:euc.txt to:@: \ + copy from:nihongo/nihongo.fnt to:@: \ + imgout:haribote.img + +#命令 + +run : + $(MAKE) haribote.img + $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../z_tools/qemu + +install : + $(MAKE) haribote.img + $(IMGTOL) w a: haribote.img + +full : + $(MAKE) -C haribote + $(MAKE) -C apilib + $(MAKE) -C a + $(MAKE) -C hello3 + $(MAKE) -C hello4 + $(MAKE) -C hello5 + $(MAKE) -C winhelo + $(MAKE) -C winhelo2 + $(MAKE) -C winhelo3 + $(MAKE) -C star1 + $(MAKE) -C stars + $(MAKE) -C stars2 + $(MAKE) -C lines + $(MAKE) -C walk + $(MAKE) -C noodle + $(MAKE) -C beepdown + $(MAKE) -C color + $(MAKE) -C color2 + $(MAKE) -C sosu + $(MAKE) -C sosu2 + $(MAKE) -C sosu3 + $(MAKE) -C typeipl + $(MAKE) -C type + $(MAKE) -C iroha + $(MAKE) -C chklang + $(MAKE) haribote.img + +run_full : + $(MAKE) full + $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../z_tools/qemu + +install_full : + $(MAKE) full + $(IMGTOL) w a: haribote.img + +run_os : + $(MAKE) -C haribote + $(MAKE) run + +clean : +#不执行任何操作 + +src_only : + $(MAKE) clean + -$(DEL) haribote.img + +clean_full : + $(MAKE) -C haribote clean + $(MAKE) -C apilib clean + $(MAKE) -C a clean + $(MAKE) -C hello3 clean + $(MAKE) -C hello4 clean + $(MAKE) -C hello5 clean + $(MAKE) -C winhelo clean + $(MAKE) -C winhelo2 clean + $(MAKE) -C winhelo3 clean + $(MAKE) -C star1 clean + $(MAKE) -C stars clean + $(MAKE) -C stars2 clean + $(MAKE) -C lines clean + $(MAKE) -C walk clean + $(MAKE) -C noodle clean + $(MAKE) -C beepdown clean + $(MAKE) -C color clean + $(MAKE) -C color2 clean + $(MAKE) -C sosu clean + $(MAKE) -C sosu2 clean + $(MAKE) -C sosu3 clean + $(MAKE) -C typeipl clean + $(MAKE) -C type clean + $(MAKE) -C iroha clean + $(MAKE) -C chklang clean + +src_only_full : + $(MAKE) -C haribote src_only + $(MAKE) -C apilib src_only + $(MAKE) -C a src_only + $(MAKE) -C hello3 src_only + $(MAKE) -C hello4 src_only + $(MAKE) -C hello5 src_only + $(MAKE) -C winhelo src_only + $(MAKE) -C winhelo2 src_only + $(MAKE) -C winhelo3 src_only + $(MAKE) -C star1 src_only + $(MAKE) -C stars src_only + $(MAKE) -C stars2 src_only + $(MAKE) -C lines src_only + $(MAKE) -C walk src_only + $(MAKE) -C noodle src_only + $(MAKE) -C beepdown src_only + $(MAKE) -C color src_only + $(MAKE) -C color2 src_only + $(MAKE) -C sosu src_only + $(MAKE) -C sosu2 src_only + $(MAKE) -C sosu3 src_only + $(MAKE) -C typeipl src_only + $(MAKE) -C type src_only + $(MAKE) -C iroha src_only + $(MAKE) -C chklang src_only + -$(DEL) haribote.img + +refresh : + $(MAKE) full + $(MAKE) clean_full + -$(DEL) haribote.img diff --git a/29_day/a/!cons_9x.bat b/29_day/a/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/a/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/a/!cons_nt.bat b/29_day/a/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/a/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/a/Makefile b/29_day/a/Makefile new file mode 100644 index 0000000..674a683 --- /dev/null +++ b/29_day/a/Makefile @@ -0,0 +1,5 @@ +APP = a +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/a/a.c b/29_day/a/a.c new file mode 100644 index 0000000..3df81f5 --- /dev/null +++ b/29_day/a/a.c @@ -0,0 +1,7 @@ +#include "apilib.h" + +void HariMain(void) +{ + api_putchar('A'); + api_end(); +} diff --git a/29_day/a/make.bat b/29_day/a/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/a/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/apilib.h b/29_day/apilib.h new file mode 100644 index 0000000..ac282d8 --- /dev/null +++ b/29_day/apilib.h @@ -0,0 +1,27 @@ +void api_putchar(int c); +void api_putstr0(char *s); +void api_putstr1(char *s, int l); +void api_end(void); +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_free(char *addr, int size); +void api_point(int win, int x, int y, int col); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +void api_closewin(int win); +int api_getkey(int mode); +int api_alloctimer(void); +void api_inittimer(int timer, int data); +void api_settimer(int timer, int time); +void api_freetimer(int timer); +void api_beep(int tone); +int api_fopen(char *fname); +void api_fclose(int fhandle); +void api_fseek(int fhandle, int offset, int mode); +int api_fsize(int fhandle, int mode); +int api_fread(char *buf, int maxsize, int fhandle); +int api_cmdline(char *buf, int maxsize); +int api_getlang(void); diff --git a/29_day/apilib/!cons_9x.bat b/29_day/apilib/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/apilib/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/apilib/!cons_nt.bat b/29_day/apilib/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/apilib/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/apilib/Makefile b/29_day/apilib/Makefile new file mode 100644 index 0000000..8ce9ef5 --- /dev/null +++ b/29_day/apilib/Makefile @@ -0,0 +1,48 @@ +OBJS_API = api001.obj api002.obj api003.obj api004.obj api005.obj api006.obj \ + api007.obj api008.obj api009.obj api010.obj api011.obj api012.obj \ + api013.obj api014.obj api015.obj api016.obj api017.obj api018.obj \ + api019.obj api020.obj api021.obj api022.obj api023.obj api024.obj \ + api025.obj api026.obj api027.obj alloca.obj + +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) apilib.lib + +#库生成规则 + +apilib.lib : Makefile $(OBJS_API) + $(GOLIB) $(OBJS_API) out:apilib.lib + +#文件生成规则 + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +#命令 + +clean : + -$(DEL) *.lst + -$(DEL) *.obj + +src_only : + $(MAKE) clean + -$(DEL) apilib.lib diff --git a/29_day/apilib/alloca.nas b/29_day/apilib/alloca.nas new file mode 100644 index 0000000..b94f8e2 --- /dev/null +++ b/29_day/apilib/alloca.nas @@ -0,0 +1,13 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "alloca.nas"] + + GLOBAL __alloca + +[SECTION .text] + +__alloca: + ADD EAX,-4 + SUB ESP,EAX + JMP DWORD [ESP+EAX] ; 代替RET diff --git a/29_day/apilib/api001.nas b/29_day/apilib/api001.nas new file mode 100644 index 0000000..2f893a9 --- /dev/null +++ b/29_day/apilib/api001.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api001.nas"] + + GLOBAL _api_putchar + +[SECTION .text] + +_api_putchar: ; void api_putchar(int c); + MOV EDX,1 + MOV AL,[ESP+4] ; c + INT 0x40 + RET diff --git a/29_day/apilib/api002.nas b/29_day/apilib/api002.nas new file mode 100644 index 0000000..6ac9cc7 --- /dev/null +++ b/29_day/apilib/api002.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api002.nas"] + + GLOBAL _api_putstr0 + +[SECTION .text] + +_api_putstr0: ; void api_putstr0(char *s); + PUSH EBX + MOV EDX,2 + MOV EBX,[ESP+8] ; s + INT 0x40 + POP EBX + RET diff --git a/29_day/apilib/api003.nas b/29_day/apilib/api003.nas new file mode 100644 index 0000000..6c2d0fd --- /dev/null +++ b/29_day/apilib/api003.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api003.nas"] + + GLOBAL _api_putstr1 + +[SECTION .text] + +_api_putstr1: ; void api_putstr1(char *s, int l); + PUSH EBX + MOV EDX,3 + MOV EBX,[ESP+ 8] ; s + MOV ECX,[ESP+12] ; l + INT 0x40 + POP EBX + RET diff --git a/29_day/apilib/api004.nas b/29_day/apilib/api004.nas new file mode 100644 index 0000000..3c738a3 --- /dev/null +++ b/29_day/apilib/api004.nas @@ -0,0 +1,12 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api004.nas"] + + GLOBAL _api_end + +[SECTION .text] + +_api_end: ; void api_end(void); + MOV EDX,4 + INT 0x40 diff --git a/29_day/apilib/api005.nas b/29_day/apilib/api005.nas new file mode 100644 index 0000000..2157c61 --- /dev/null +++ b/29_day/apilib/api005.nas @@ -0,0 +1,24 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api005.nas"] + + GLOBAL _api_openwin + +[SECTION .text] + +_api_openwin: ; int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,5 + MOV EBX,[ESP+16] ; buf + MOV ESI,[ESP+20] ; xsiz + MOV EDI,[ESP+24] ; ysiz + MOV EAX,[ESP+28] ; col_inv + MOV ECX,[ESP+32] ; title + INT 0x40 + POP EBX + POP ESI + POP EDI + RET diff --git a/29_day/apilib/api006.nas b/29_day/apilib/api006.nas new file mode 100644 index 0000000..94cbb2d --- /dev/null +++ b/29_day/apilib/api006.nas @@ -0,0 +1,27 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api006.nas"] + + GLOBAL _api_putstrwin + +[SECTION .text] + +_api_putstrwin: ; void api_putstrwin(int win, int x, int y, int col, int len, char *str); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,6 + MOV EBX,[ESP+20] ; win + MOV ESI,[ESP+24] ; x + MOV EDI,[ESP+28] ; y + MOV EAX,[ESP+32] ; col + MOV ECX,[ESP+36] ; len + MOV EBP,[ESP+40] ; str + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET diff --git a/29_day/apilib/api007.nas b/29_day/apilib/api007.nas new file mode 100644 index 0000000..57be736 --- /dev/null +++ b/29_day/apilib/api007.nas @@ -0,0 +1,27 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api007.nas"] + + GLOBAL _api_boxfilwin + +[SECTION .text] + +_api_boxfilwin: ; void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,7 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET diff --git a/29_day/apilib/api008.nas b/29_day/apilib/api008.nas new file mode 100644 index 0000000..d1ed6c7 --- /dev/null +++ b/29_day/apilib/api008.nas @@ -0,0 +1,20 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api008.nas"] + + GLOBAL _api_initmalloc + +[SECTION .text] + +_api_initmalloc: ; void api_initmalloc(void); + PUSH EBX + MOV EDX,8 + MOV EBX,[CS:0x0020] ; malloc内存空间的地址 + MOV EAX,EBX + ADD EAX,32*1024 ; 加上32KB + MOV ECX,[CS:0x0000] ; 数据段的大小 + SUB ECX,EAX + INT 0x40 + POP EBX + RET diff --git a/29_day/apilib/api009.nas b/29_day/apilib/api009.nas new file mode 100644 index 0000000..bcd5307 --- /dev/null +++ b/29_day/apilib/api009.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api009.nas"] + + GLOBAL _api_malloc + +[SECTION .text] + +_api_malloc: ; char *api_malloc(int size); + PUSH EBX + MOV EDX,9 + MOV EBX,[CS:0x0020] + MOV ECX,[ESP+8] ; size + INT 0x40 + POP EBX + RET diff --git a/29_day/apilib/api010.nas b/29_day/apilib/api010.nas new file mode 100644 index 0000000..63a4ea5 --- /dev/null +++ b/29_day/apilib/api010.nas @@ -0,0 +1,18 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api010.nas"] + + GLOBAL _api_free + +[SECTION .text] + +_api_free: ; void api_free(char *addr, int size); + PUSH EBX + MOV EDX,10 + MOV EBX,[CS:0x0020] + MOV EAX,[ESP+ 8] ; addr + MOV ECX,[ESP+12] ; size + INT 0x40 + POP EBX + RET diff --git a/29_day/apilib/api011.nas b/29_day/apilib/api011.nas new file mode 100644 index 0000000..f5994b9 --- /dev/null +++ b/29_day/apilib/api011.nas @@ -0,0 +1,23 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api011.nas"] + + GLOBAL _api_point + +[SECTION .text] + +_api_point: ; void api_point(int win, int x, int y, int col); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,11 + MOV EBX,[ESP+16] ; win + MOV ESI,[ESP+20] ; x + MOV EDI,[ESP+24] ; y + MOV EAX,[ESP+28] ; col + INT 0x40 + POP EBX + POP ESI + POP EDI + RET diff --git a/29_day/apilib/api012.nas b/29_day/apilib/api012.nas new file mode 100644 index 0000000..9e9386f --- /dev/null +++ b/29_day/apilib/api012.nas @@ -0,0 +1,24 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api012.nas"] + + GLOBAL _api_refreshwin + +[SECTION .text] + +_api_refreshwin: ; void api_refreshwin(int win, int x0, int y0, int x1, int y1); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,12 + MOV EBX,[ESP+16] ; win + MOV EAX,[ESP+20] ; x0 + MOV ECX,[ESP+24] ; y0 + MOV ESI,[ESP+28] ; x1 + MOV EDI,[ESP+32] ; y1 + INT 0x40 + POP EBX + POP ESI + POP EDI + RET diff --git a/29_day/apilib/api013.nas b/29_day/apilib/api013.nas new file mode 100644 index 0000000..017f1ea --- /dev/null +++ b/29_day/apilib/api013.nas @@ -0,0 +1,27 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api013.nas"] + + GLOBAL _api_linewin + +[SECTION .text] + +_api_linewin: ; void api_linewin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,13 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET diff --git a/29_day/apilib/api014.nas b/29_day/apilib/api014.nas new file mode 100644 index 0000000..363db51 --- /dev/null +++ b/29_day/apilib/api014.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api014.nas"] + + GLOBAL _api_closewin + +[SECTION .text] + +_api_closewin: ; void api_closewin(int win); + PUSH EBX + MOV EDX,14 + MOV EBX,[ESP+8] ; win + INT 0x40 + POP EBX + RET diff --git a/29_day/apilib/api015.nas b/29_day/apilib/api015.nas new file mode 100644 index 0000000..bd27ec7 --- /dev/null +++ b/29_day/apilib/api015.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api015.nas"] + + GLOBAL _api_getkey + +[SECTION .text] + +_api_getkey: ; int api_getkey(int mode); + MOV EDX,15 + MOV EAX,[ESP+4] ; mode + INT 0x40 + RET diff --git a/29_day/apilib/api016.nas b/29_day/apilib/api016.nas new file mode 100644 index 0000000..e232412 --- /dev/null +++ b/29_day/apilib/api016.nas @@ -0,0 +1,13 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api016.nas"] + + GLOBAL _api_alloctimer + +[SECTION .text] + +_api_alloctimer: ; int api_alloctimer(void); + MOV EDX,16 + INT 0x40 + RET diff --git a/29_day/apilib/api017.nas b/29_day/apilib/api017.nas new file mode 100644 index 0000000..9e6a3cd --- /dev/null +++ b/29_day/apilib/api017.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api017.nas"] + + GLOBAL _api_inittimer + +[SECTION .text] + +_api_inittimer: ; void api_inittimer(int timer, int data); + PUSH EBX + MOV EDX,17 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; data + INT 0x40 + POP EBX + RET diff --git a/29_day/apilib/api018.nas b/29_day/apilib/api018.nas new file mode 100644 index 0000000..a91d6f1 --- /dev/null +++ b/29_day/apilib/api018.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api018.nas"] + + GLOBAL _api_settimer + +[SECTION .text] + +_api_settimer: ; void api_settimer(int timer, int time); + PUSH EBX + MOV EDX,18 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; time + INT 0x40 + POP EBX + RET diff --git a/29_day/apilib/api019.nas b/29_day/apilib/api019.nas new file mode 100644 index 0000000..d1c11e2 --- /dev/null +++ b/29_day/apilib/api019.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api019.nas"] + + GLOBAL _api_freetimer + +[SECTION .text] + +_api_freetimer: ; void api_freetimer(int timer); + PUSH EBX + MOV EDX,19 + MOV EBX,[ESP+ 8] ; timer + INT 0x40 + POP EBX + RET diff --git a/29_day/apilib/api020.nas b/29_day/apilib/api020.nas new file mode 100644 index 0000000..166bcda --- /dev/null +++ b/29_day/apilib/api020.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api020.nas"] + + GLOBAL _api_beep + +[SECTION .text] + +_api_beep: ; void api_beep(int tone); + MOV EDX,20 + MOV EAX,[ESP+4] ; tone + INT 0x40 + RET diff --git a/29_day/apilib/api021.nas b/29_day/apilib/api021.nas new file mode 100644 index 0000000..565a037 --- /dev/null +++ b/29_day/apilib/api021.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api021.nas"] + + GLOBAL _api_fopen + +[SECTION .text] + +_api_fopen: ; int api_fopen(char *fname); + PUSH EBX + MOV EDX,21 + MOV EBX,[ESP+8] ; fname + INT 0x40 + POP EBX + RET diff --git a/29_day/apilib/api022.nas b/29_day/apilib/api022.nas new file mode 100644 index 0000000..a21f508 --- /dev/null +++ b/29_day/apilib/api022.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api022.nas"] + + GLOBAL _api_fclose + +[SECTION .text] + +_api_fclose: ; void api_fclose(int fhandle); + MOV EDX,22 + MOV EAX,[ESP+4] ; fhandle + INT 0x40 + RET diff --git a/29_day/apilib/api023.nas b/29_day/apilib/api023.nas new file mode 100644 index 0000000..f34c33b --- /dev/null +++ b/29_day/apilib/api023.nas @@ -0,0 +1,18 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api023.nas"] + + GLOBAL _api_fseek + +[SECTION .text] + +_api_fseek: ; void api_fseek(int fhandle, int offset, int mode); + PUSH EBX + MOV EDX,23 + MOV EAX,[ESP+8] ; fhandle + MOV ECX,[ESP+16] ; mode + MOV EBX,[ESP+12] ; offset + INT 0x40 + POP EBX + RET diff --git a/29_day/apilib/api024.nas b/29_day/apilib/api024.nas new file mode 100644 index 0000000..5352889 --- /dev/null +++ b/29_day/apilib/api024.nas @@ -0,0 +1,15 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api024.nas"] + + GLOBAL _api_fsize + +[SECTION .text] + +_api_fsize: ; int api_fsize(int fhandle, int mode); + MOV EDX,24 + MOV EAX,[ESP+4] ; fhandle + MOV ECX,[ESP+8] ; mode + INT 0x40 + RET diff --git a/29_day/apilib/api025.nas b/29_day/apilib/api025.nas new file mode 100644 index 0000000..9f394d3 --- /dev/null +++ b/29_day/apilib/api025.nas @@ -0,0 +1,18 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api025.nas"] + + GLOBAL _api_fread + +[SECTION .text] + +_api_fread: ; int api_fread(char *buf, int maxsize, int fhandle); + PUSH EBX + MOV EDX,25 + MOV EAX,[ESP+16] ; fhandle + MOV ECX,[ESP+12] ; maxsize + MOV EBX,[ESP+8] ; buf + INT 0x40 + POP EBX + RET diff --git a/29_day/apilib/api026.nas b/29_day/apilib/api026.nas new file mode 100644 index 0000000..33bb2f5 --- /dev/null +++ b/29_day/apilib/api026.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api026.nas"] + + GLOBAL _api_cmdline + +[SECTION .text] + +_api_cmdline: ; int api_cmdline(char *buf, int maxsize); + PUSH EBX + MOV EDX,26 + MOV ECX,[ESP+12] ; maxsize + MOV EBX,[ESP+8] ; buf + INT 0x40 + POP EBX + RET diff --git a/29_day/apilib/api027.nas b/29_day/apilib/api027.nas new file mode 100644 index 0000000..38bfbc1 --- /dev/null +++ b/29_day/apilib/api027.nas @@ -0,0 +1,13 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api027.nas"] + + GLOBAL _api_getlang + +[SECTION .text] + +_api_getlang: ; int api_getlang(void); + MOV EDX,27 + INT 0x40 + RET diff --git a/29_day/apilib/apilib.lib b/29_day/apilib/apilib.lib new file mode 100644 index 0000000000000000000000000000000000000000..29a8eeebd154eb753bb6d0e59a2125dff5d57df1 GIT binary patch literal 8966 zcmeI2&uv5w%5XY3zgzHW)jywS}zIi{^ zs~^`oyY){J*V10ed5ca-)fYK*TCxI?b?20d;e=|w_fW&6}na@=PnqsV7Bha zllH#Z`liuxcX5h4?T34frc-RR8rFkav)SI2z1`<~9n-YOXg6AxJnfiN-K{$VG#f3` zDeN}e-9hQDY27!!m6wTISd9m!{SkCHS})$E;`RZ|rK z#|@ljv<` zk{TKXJq@0(S4Kv|fTU3jLBsIt#Z#JokY1dkHm1RSlte+J&l|wuM!?oo)Fa?YdgWaq z5Jr@J91^)TiH%C^Mx_v|Uh=Q{?=)o4s((anyz1OXNffL8`Da^wa!*(bQavlP)H}#5 z_bQnc(ug!^#8=xvJ5)&zgy-*-cLjt;4X_o;1C=^a4ne2vx7mNteS+v*rZ%R-eUwB) z=hLk|d5(-{iSR5Fo)yBACOny5Gjo{`-413{)-&R#@Je)y7U@RHA0;cozPqG!{eMD< zcOXHjLX}Af!2ca!tG6Ds^wv0udn73()F@y8O#*o;b z_d>5k$H8&G?9V=eLYT<^1PVXU?+X7jr?#AXi()kkTw9nBbg=@*)j4->8D{hBcrR-3nB Wt<|Qd)cUcbwAxHvcu(R_7XJe03V>?> literal 0 HcmV?d00001 diff --git a/29_day/apilib/make.bat b/29_day/apilib/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/apilib/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/app_make.txt b/29_day/app_make.txt new file mode 100644 index 0000000..2bca4bc --- /dev/null +++ b/29_day/app_make.txt @@ -0,0 +1,79 @@ +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ +APILIBPATH = ../apilib/ +HARIBOTEPATH = ../haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -I../ -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) $(APP).hrb + +#文件生成规则 + +$(APP).bim : $(APP).obj $(APILIBPATH)apilib.lib Makefile ../app_make.txt + $(OBJ2BIM) @$(RULEFILE) out:$(APP).bim map:$(APP).map stack:$(STACK) \ + $(APP).obj $(APILIBPATH)apilib.lib + +$(APP).hrb : $(APP).bim Makefile ../app_make.txt + $(BIM2HRB) $(APP).bim $(APP).hrb $(MALLOC) + +haribote.img : ../haribote/ipl10.bin ../haribote/haribote.sys $(APP).hrb \ + Makefile ../app_make.txt + $(EDIMG) imgin:../../z_tools/fdimg0at.tek \ + wbinimg src:../haribote/ipl10.bin len:512 from:0 to:0 \ + copy from:../haribote/haribote.sys to:@: \ + copy from:$(APP).hrb to:@: \ + imgout:haribote.img + +#一般规则 + +%.gas : %.c ../apilib.h Makefile ../app_make.txt + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile ../app_make.txt + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile ../app_make.txt + $(NASK) $*.nas $*.obj $*.lst + +#命令 + +run : + $(MAKE) haribote.img + $(COPY) haribote.img ..\..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../../z_tools/qemu + +full : + $(MAKE) -C $(APILIBPATH) + $(MAKE) $(APP).hrb + +run_full : + $(MAKE) -C $(APILIBPATH) + $(MAKE) -C ../haribote + $(MAKE) run + +clean : + -$(DEL) *.lst + -$(DEL) *.obj + -$(DEL) *.map + -$(DEL) *.bim + -$(DEL) haribote.img + +src_only : + $(MAKE) clean + -$(DEL) $(APP).hrb diff --git a/29_day/beepdown/!cons_9x.bat b/29_day/beepdown/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/beepdown/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/beepdown/!cons_nt.bat b/29_day/beepdown/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/beepdown/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/beepdown/Makefile b/29_day/beepdown/Makefile new file mode 100644 index 0000000..ffd14fa --- /dev/null +++ b/29_day/beepdown/Makefile @@ -0,0 +1,5 @@ +APP = beepdown +STACK = 1k +MALLOC = 40k + +include ../app_make.txt diff --git a/29_day/beepdown/beepdown.c b/29_day/beepdown/beepdown.c new file mode 100644 index 0000000..d08962c --- /dev/null +++ b/29_day/beepdown/beepdown.c @@ -0,0 +1,19 @@ +#include "apilib.h" + +void HariMain(void) +{ + int i, timer; + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (i = 20000000; i >= 20000; i -= i / 100) { + /* 20KHz~20Hz,即人类可以听到的声音范围*/ + /* i以1%的速度递减*/ + api_beep(i); + api_settimer(timer, 1); /* 0.01秒*/ + if (api_getkey(1) != 128) { + break; + } + } + api_beep(0); + api_end(); +} diff --git a/29_day/beepdown/make.bat b/29_day/beepdown/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/beepdown/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/chklang/!cons_9x.bat b/29_day/chklang/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/chklang/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/chklang/!cons_nt.bat b/29_day/chklang/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/chklang/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/chklang/Makefile b/29_day/chklang/Makefile new file mode 100644 index 0000000..c00ebbc --- /dev/null +++ b/29_day/chklang/Makefile @@ -0,0 +1,5 @@ +APP = chklang +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/chklang/chklang.c b/29_day/chklang/chklang.c new file mode 100644 index 0000000..3c28491 --- /dev/null +++ b/29_day/chklang/chklang.c @@ -0,0 +1,24 @@ +#include "apilib.h" + +void HariMain(void) +{ + int langmode = api_getlang(); + static char s1[23] = { /* 日本語シフトJISモード(日文Shift-JIS模式)*/ + 0x93, 0xfa, 0x96, 0x7b, 0x8c, 0xea, 0x83, 0x56, 0x83, 0x74, 0x83, 0x67, + 0x4a, 0x49, 0x53, 0x83, 0x82, 0x81, 0x5b, 0x83, 0x68, 0x0a, 0x00 + }; + static char s2[17] = { /*日本語EUCモード(日文EUC模式)*/ + 0xc6, 0xfc, 0xcb, 0xdc, 0xb8, 0xec, 0x45, 0x55, 0x43, 0xa5, 0xe2, 0xa1, + 0xbc, 0xa5, 0xc9, 0x0a, 0x00 + }; + if (langmode == 0) { + api_putstr0("English ASCII mode\n"); + } + if (langmode == 1) { + api_putstr0(s1); + } + if (langmode == 2) { + api_putstr0(s2); + } + api_end(); +} diff --git a/29_day/chklang/make.bat b/29_day/chklang/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/chklang/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/color/!cons_9x.bat b/29_day/color/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/color/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/color/!cons_nt.bat b/29_day/color/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/color/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/color/Makefile b/29_day/color/Makefile new file mode 100644 index 0000000..614dac9 --- /dev/null +++ b/29_day/color/Makefile @@ -0,0 +1,5 @@ +APP = color +STACK = 1k +MALLOC = 56k + +include ../app_make.txt diff --git a/29_day/color/color.c b/29_day/color/color.c new file mode 100644 index 0000000..ce228e2 --- /dev/null +++ b/29_day/color/color.c @@ -0,0 +1,21 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win, x, y, r, g, b; + api_initmalloc(); + buf = api_malloc(144 * 164); + win = api_openwin(buf, 144, 164, -1, "color"); + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) { + r = x * 2; + g = y * 2; + b = 0; + buf[(x + 8) + (y + 28) * 144] = 16 + (r / 43) + (g / 43) * 6 + (b / 43) * 36; + } + } + api_refreshwin(win, 8, 28, 136, 156); + api_getkey(1); /*等待按下任意键*/ + api_end(); +} diff --git a/29_day/color/make.bat b/29_day/color/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/color/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/color2/!cons_9x.bat b/29_day/color2/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/color2/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/color2/!cons_nt.bat b/29_day/color2/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/color2/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/color2/Makefile b/29_day/color2/Makefile new file mode 100644 index 0000000..93b5f23 --- /dev/null +++ b/29_day/color2/Makefile @@ -0,0 +1,5 @@ +APP = color2 +STACK = 1k +MALLOC = 56k + +include ../app_make.txt diff --git a/29_day/color2/color2.c b/29_day/color2/color2.c new file mode 100644 index 0000000..82e3f6a --- /dev/null +++ b/29_day/color2/color2.c @@ -0,0 +1,36 @@ +#include "apilib.h" + +unsigned char rgb2pal(int r, int g, int b, int x, int y); + +void HariMain(void) +{ + char *buf; + int win, x, y; + api_initmalloc(); + buf = api_malloc(144 * 164); + win = api_openwin(buf, 144, 164, -1, "color2"); + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) { + buf[(x + 8) + (y + 28) * 144] = rgb2pal(x * 2, y * 2, 0, x, y); + } + } + api_refreshwin(win, 8, 28, 136, 156); + api_getkey(1); /* �Ă��Ƃ��ȃL�[���͂�҂� */ + api_end(); +} + +unsigned char rgb2pal(int r, int g, int b, int x, int y) +{ + static int table[4] = { 3, 1, 0, 2 }; + int i; + x &= 1; /*判断是偶数还是奇数*/ + y &= 1; + i = table[x + y * 2]; /*用来生成中间色的常量*/ + r = (r * 21) / 256; /* r为0~20*/ + g = (g * 21) / 256; + b = (b * 21) / 256; + r = (r + i) / 4; /* r为0~5*/ + g = (g + i) / 4; + b = (b + i) / 4; + return 16 + r + g * 6 + b * 36; +} diff --git a/29_day/color2/make.bat b/29_day/color2/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/color2/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/euc.txt b/29_day/euc.txt new file mode 100644 index 0000000..ae6d81a --- /dev/null +++ b/29_day/euc.txt @@ -0,0 +1 @@ +ܸEUCǽ񤤤Ƥߤ衼 diff --git a/29_day/haribote.rul b/29_day/haribote.rul new file mode 100644 index 0000000..ee8f67b --- /dev/null +++ b/29_day/haribote.rul @@ -0,0 +1,10 @@ +format: + code(align:1, logic:0x24, file:0x24); + data(align:4, logic:stack_end, file:code_end); + +file: + ../../z_tools/haribote/harilibc.lib; + ../../z_tools/haribote/golibc.lib; + +label: + _HariStartup; diff --git a/29_day/haribote/!cons_9x.bat b/29_day/haribote/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/haribote/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/haribote/!cons_nt.bat b/29_day/haribote/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/haribote/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/haribote/Makefile b/29_day/haribote/Makefile new file mode 100644 index 0000000..374bba7 --- /dev/null +++ b/29_day/haribote/Makefile @@ -0,0 +1,83 @@ +OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \ + int.obj fifo.obj keyboard.obj mouse.obj memory.obj sheet.obj timer.obj \ + mtask.obj window.obj console.obj file.obj + +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) ipl20.bin + $(MAKE) haribote.sys + +# 镜像文件生成 + +ipl10.bin : ipl10.nas Makefile + $(NASK) ipl10.nas ipl10.bin ipl10.lst + +ipl20.bin : ipl20.nas Makefile + $(NASK) ipl20.nas ipl20.bin ipl20.lst + +asmhead.bin : asmhead.nas Makefile + $(NASK) asmhead.nas asmhead.bin asmhead.lst + +hankaku.bin : hankaku.txt Makefile + $(MAKEFONT) hankaku.txt hankaku.bin + +hankaku.obj : hankaku.bin Makefile + $(BIN2OBJ) hankaku.bin hankaku.obj _hankaku + +bootpack.bim : $(OBJS_BOOTPACK) Makefile + $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \ + $(OBJS_BOOTPACK) +# 3MB+64KB=3136KB + +bootpack.hrb : bootpack.bim Makefile + $(BIM2HRB) bootpack.bim bootpack.hrb 0 + +haribote.sys : asmhead.bin bootpack.hrb Makefile + copy /B asmhead.bin+bootpack.hrb haribote.sys + +# 其他指令 + +%.gas : %.c bootpack.h Makefile + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +# 运行程序 + +clean : + -$(DEL) asmhead.bin + -$(DEL) hankaku.bin + -$(DEL) *.lst + -$(DEL) *.obj + -$(DEL) *.map + -$(DEL) *.bim + -$(DEL) *.hrb + +src_only : + $(MAKE) clean + -$(DEL) ipl10.bin + -$(DEL) ipl20.bin + -$(DEL) haribote.sys diff --git a/29_day/haribote/asmhead.nas b/29_day/haribote/asmhead.nas new file mode 100644 index 0000000..ad35d76 --- /dev/null +++ b/29_day/haribote/asmhead.nas @@ -0,0 +1,202 @@ +; haribote-os boot asm +; TAB=4 + +[INSTRSET "i486p"] + +VBEMODE EQU 0x105 ; 1024 x 768 x 8bit 彩色 +; 显示模式 +; 0x100 : 640 x 400 x 8bit 彩色 +; 0x101 : 640 x 480 x 8bit 彩色 +; 0x103 : 800 x 600 x 8bit 彩色 +; 0x105 : 1024 x 768 x 8bit 彩色 +; 0x107 : 1280 x 1024 x 8bit 彩色 + +BOTPAK EQU 0x00280000 ; 加载bootpack +DSKCAC EQU 0x00100000 ; 磁盘缓存的位置 +DSKCAC0 EQU 0x00008000 ; 磁盘缓存的位置(实模式) + +; BOOT_INFO 相关 +CYLS EQU 0x0ff0 ; 引导扇区设置 +LEDS EQU 0x0ff1 +VMODE EQU 0x0ff2 ; 关于颜色的信息 +SCRNX EQU 0x0ff4 ; 分辨率X +SCRNY EQU 0x0ff6 ; 分辨率Y +VRAM EQU 0x0ff8 ; 图像缓冲区的起始地址 + + ORG 0xc200 ; 这个的程序要被装载的内存地址 + +; 确认VBE是否存在 + + MOV AX,0x9000 + MOV ES,AX + MOV DI,0 + MOV AX,0x4f00 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 检查VBE的版本 + + MOV AX,[ES:DI+4] + CMP AX,0x0200 + JB scrn320 ; if (AX < 0x0200) goto scrn320 + +; 取得画面模式信息 + + MOV CX,VBEMODE + MOV AX,0x4f01 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 画面模式信息的确认 + CMP BYTE [ES:DI+0x19],8 ;颜色数必须为8 + JNE scrn320 + CMP BYTE [ES:DI+0x1b],4 ;颜色的指定方法必须为4(4是调色板模式) + JNE scrn320 + MOV AX,[ES:DI+0x00] ;模式属性bit7不是1就不能加上0x4000 + AND AX,0x0080 + JZ scrn320 ; 模式属性的bit7是0,所以放弃 + +; 画面设置 + + MOV BX,VBEMODE+0x4000 + MOV AX,0x4f02 + INT 0x10 + MOV BYTE [VMODE],8 ; 屏幕的模式(参考C语言的引用) + MOV AX,[ES:DI+0x12] + MOV [SCRNX],AX + MOV AX,[ES:DI+0x14] + MOV [SCRNY],AX + MOV EAX,[ES:DI+0x28] ;VRAM的地址 + MOV [VRAM],EAX + JMP keystatus + +scrn320: + MOV AL,0x13 ; VGA图、320x200x8bit彩色 + MOV AH,0x00 + INT 0x10 + MOV BYTE [VMODE],8 ; 记下画面模式(参考C语言) + MOV WORD [SCRNX],320 + MOV WORD [SCRNY],200 + MOV DWORD [VRAM],0x000a0000 + +; 通过 BIOS 获取指示灯状态 + +keystatus: + MOV AH,0x02 + INT 0x16 ; keyboard BIOS + MOV [LEDS],AL + +; PIC关闭一切中断 +; 根据AT兼容机的规格,如果要初始化PIC, +; 必须在CLI之前进行,否则有时会挂起。 +; 随后进行PIC的初始化。 + + MOV AL,0xff + OUT 0x21,AL + NOP ; 如果连续执行OUT指令,有些机种会无法正常运行 + OUT 0xa1,AL + + CLI ; 禁止CPU级别的中断 + +; 为了让CPU能够访问1MB以上的内存空间,设定A20GATE + + CALL waitkbdout + MOV AL,0xd1 + OUT 0x64,AL + CALL waitkbdout + MOV AL,0xdf ; enable A20 + OUT 0x60,AL + CALL waitkbdout + +; 切换到保护模式 + +[INSTRSET "i486p"] ; 说明使用486指令 + + LGDT [GDTR0] ; 设置临时GDT + MOV EAX,CR0 + AND EAX,0x7fffffff ; 设bit31为0(禁用分页) + OR EAX,0x00000001 ; bit0到1转换(保护模式过渡) + MOV CR0,EAX + JMP pipelineflush +pipelineflush: + MOV AX,1*8 ; 可读写的段 32bit + MOV DS,AX + MOV ES,AX + MOV FS,AX + MOV GS,AX + MOV SS,AX + +; bootpack传递 + + MOV ESI,bootpack ; 转送源 + MOV EDI,BOTPAK ; 转送目标 + MOV ECX,512*1024/4 + CALL memcpy + +; 磁盘数据最终转送到它本来的位置去 +; 首先从启动扇区开始 + + MOV ESI,0x7c00 ; 转送源 + MOV EDI,DSKCAC ; 转送目标 + MOV ECX,512/4 + CALL memcpy + +; 剩余的全部 + + MOV ESI,DSKCAC0+512 ; 转送源 + MOV EDI,DSKCAC+512 ; 转送源目标 + MOV ECX,0 + MOV CL,BYTE [CYLS] + IMUL ECX,512*18*2/4 ; 从柱面数变换为字节数/4 + SUB ECX,512/4 ; 减去 IPL 偏移量 + CALL memcpy + +; 必须由asmhead来完成的工作,至此全部完毕 +; 以后就交由bootpack来完成 + +; bootpack启动 + + MOV EBX,BOTPAK + MOV ECX,[EBX+16] + ADD ECX,3 ; ECX += 3; + SHR ECX,2 ; ECX /= 4; + JZ skip ; 没有要转送的东西时 + MOV ESI,[EBX+20] ; 转送源 + ADD ESI,EBX + MOV EDI,[EBX+12] ; 转送目标 + CALL memcpy +skip: + MOV ESP,[EBX+12] ; 堆栈的初始化 + JMP DWORD 2*8:0x0000001b + +waitkbdout: + IN AL,0x64 + AND AL,0x02 + JNZ waitkbdout ; AND的结果如果不是0,就跳到waitkbdout + RET + +memcpy: + MOV EAX,[ESI] + ADD ESI,4 + MOV [EDI],EAX + ADD EDI,4 + SUB ECX,1 + JNZ memcpy ; 减法运算的结果如果不是0,就跳转到memcpy + RET +; memcpy地址前缀大小 + + ALIGNB 16 +GDT0: + RESB 8 ; 初始值 + DW 0xffff,0x0000,0x9200,0x00cf ; 可以读写的段(segment)32bit + DW 0xffff,0x0000,0x9a28,0x0047 ; 可执行的文件的32bit寄存器(bootpack用) + + DW 0 +GDTR0: + DW 8*3-1 + DD GDT0 + + ALIGNB 16 +bootpack: diff --git a/29_day/haribote/bootpack.c b/29_day/haribote/bootpack.c new file mode 100644 index 0000000..92754c6 --- /dev/null +++ b/29_day/haribote/bootpack.c @@ -0,0 +1,410 @@ +/* bootpack */ + +#include "bootpack.h" +#include + +#define KEYCMD_LED 0xed + +void keywin_off(struct SHEET *key_win); +void keywin_on(struct SHEET *key_win); +void close_console(struct SHEET *sht); +void close_constask(struct TASK *task); + +void HariMain(void) +{ + struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; + struct SHTCTL *shtctl; + char s[40]; + struct FIFO32 fifo, keycmd; + int fifobuf[128], keycmd_buf[32]; + int mx, my, i, new_mx = -1, new_my = 0, new_wx = 0x7fffffff, new_wy = 0; + unsigned int memtotal; + struct MOUSE_DEC mdec; + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + unsigned char *buf_back, buf_mouse[256]; + struct SHEET *sht_back, *sht_mouse; + struct TASK *task_a, *task; + static char keytable0[0x80] = { + 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0x08, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0x0a, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0 + }; + static char keytable1[0x80] = { + 0, 0, '!', 0x22, '#', '$', '%', '&', 0x27, '(', ')', '~', '=', '~', 0x08, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0x0a, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', '+', '*', 0, 0, '}', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, '|', 0, 0 + }; + int key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; + int j, x, y, mmx = -1, mmy = -1, mmx2 = 0; + struct SHEET *sht = 0, *key_win, *sht2; + int *fat; + unsigned char *nihongo; + struct FILEINFO *finfo; + extern char hankaku[4096]; + + init_gdtidt(); + init_pic(); + io_sti(); /* IDT/PIC的初始化已经完成,于是开放CPU的中断 */ + fifo32_init(&fifo, 128, fifobuf, 0); + *((int *) 0x0fec) = (int) &fifo; + init_pit(); + init_keyboard(&fifo, 256); + enable_mouse(&fifo, 512, &mdec); + io_out8(PIC0_IMR, 0xf8); /* 设定PIT和PIC1以及键盘为许可(11111000) */ + io_out8(PIC1_IMR, 0xef); /* 开放鼠标中断(11101111) */ + fifo32_init(&keycmd, 32, keycmd_buf, 0); + + memtotal = memtest(0x00400000, 0xbfffffff); + memman_init(memman); + memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */ + memman_free(memman, 0x00400000, memtotal - 0x00400000); + + init_palette(); + shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny); + task_a = task_init(memman); + fifo.task = task_a; + task_run(task_a, 1, 2); + *((int *) 0x0fe4) = (int) shtctl; + task_a->langmode = 0; + + /* sht_back */ + sht_back = sheet_alloc(shtctl); + buf_back = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny); + sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 无透明色 */ + init_screen8(buf_back, binfo->scrnx, binfo->scrny); + + /* sht_cons */ + key_win = open_console(shtctl, memtotal); + + /* sht_mouse */ + sht_mouse = sheet_alloc(shtctl); + sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99); + init_mouse_cursor8(buf_mouse, 99); + mx = (binfo->scrnx - 16) / 2; /* 计算坐标使其位于画面中央 */ + my = (binfo->scrny - 28 - 16) / 2; + + sheet_slide(sht_back, 0, 0); + sheet_slide(key_win, 32, 4); + sheet_slide(sht_mouse, mx, my); + sheet_updown(sht_back, 0); + sheet_updown(key_win, 1); + sheet_updown(sht_mouse, 2); + keywin_on(key_win); + + /* 为了避免和键盘当前状态冲突,在一开始先进行设置 */ + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + + /* 载入nihongo.fnt */ + nihongo = (unsigned char *) memman_alloc_4k(memman, 16 * 256 + 32 * 94 * 47); + fat = (int *) memman_alloc_4k(memman, 4 * 2880); + file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); + finfo = file_search("nihongo.fnt", (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + if (finfo != 0) { + file_loadfile(finfo->clustno, finfo->size, nihongo, fat, (char *) (ADR_DISKIMG + 0x003e00)); + } else { + for (i = 0; i < 16 * 256; i++) { + nihongo[i] = hankaku[i]; /* 没有字库,半角部分直接复制英文字库 */ + } + for (i = 16 * 256; i < 16 * 256 + 32 * 94 * 47; i++) { + nihongo[i] = 0xff; /* 没有字库,全角部分以0xff填充 */ + } + } + *((int *) 0x0fe8) = (int) nihongo; + memman_free_4k(memman, (int) fat, 4 * 2880); + + for (;;) { + if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0) { + /* 如果存在向键盘控制器发送的数据,则发送它 */ + keycmd_wait = fifo32_get(&keycmd); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + io_cli(); + if (fifo32_status(&fifo) == 0) { + /* FIFO为空,当存在搁置的绘图操作时立即执行*/ + if (new_mx >= 0) { + io_sti(); + sheet_slide(sht_mouse, new_mx, new_my); + new_mx = -1; + } else if (new_wx != 0x7fffffff) { + io_sti(); + sheet_slide(sht, new_wx, new_wy); + new_wx = 0x7fffffff; + } else { + task_sleep(task_a); + io_sti(); + } + } else { + i = fifo32_get(&fifo); + io_sti(); + if (key_win != 0 && key_win->flags == 0) { /*窗口被关闭*/ + if (shtctl->top == 1) { /*当画面上只剩鼠标和背景时*/ + key_win = 0; + } else { + key_win = shtctl->sheets[shtctl->top - 1]; + keywin_on(key_win); + } + } + if (256 <= i && i <= 511) { /* 键盘数据*/ + if (i < 0x80 + 256) { /*将按键编码转换为字符编码*/ + if (key_shift == 0) { + s[0] = keytable0[i - 256]; + } else { + s[0] = keytable1[i - 256]; + } + } else { + s[0] = 0; + } + if ('A' <= s[0] && s[0] <= 'Z') { /*当输入字符为英文字母时*/ + if (((key_leds & 4) == 0 && key_shift == 0) || + ((key_leds & 4) != 0 && key_shift != 0)) { + s[0] += 0x20; /*将大写字母转换为小写字母*/ + } + } + if (s[0] != 0 && key_win != 0) { /*一般字符、退格键、回车键*/ + fifo32_put(&key_win->task->fifo, s[0] + 256); + } + if (i == 256 + 0x0f && key_win != 0) { /* Tab键 */ + keywin_off(key_win); + j = key_win->height - 1; + if (j == 0) { + j = shtctl->top - 1; + } + key_win = shtctl->sheets[j]; + keywin_on(key_win); + } + if (i == 256 + 0x2a) { /*左Shift ON */ + key_shift |= 1; + } + if (i == 256 + 0x36) { /*右Shift ON */ + key_shift |= 2; + } + if (i == 256 + 0xaa) { /*左Shift OFF */ + key_shift &= ~1; + } + if (i == 256 + 0xb6) { /*右Shift OFF */ + key_shift &= ~2; + } + if (i == 256 + 0x3a) { /* CapsLock */ + key_leds ^= 4; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x45) { /* NumLock */ + key_leds ^= 2; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x46) { /* ScrollLock */ + key_leds ^= 1; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x3b && key_shift != 0 && key_win != 0) { /* Shift+F1 */ + task = key_win->task; + if (task != 0 && task->tss.ss0 != 0) { + cons_putstr0(task->cons, "\nBreak(key) :\n"); + io_cli(); /*强制结束处理时禁止任务切换*/ + task->tss.eax = (int) &(task->tss.esp0); + task->tss.eip = (int) asm_end_app; + io_sti(); + task_run(task, -1, 0); /*为了确实执行结束处理,如果处于休眠状态则唤醒*/ + } + } + if (i == 256 + 0x3c && key_shift != 0) { /* Shift+F2 */ + if (key_win != 0) { + keywin_off(key_win); + } + key_win = open_console(shtctl, memtotal); + sheet_slide(key_win, 32, 4); + sheet_updown(key_win, shtctl->top); + keywin_on(key_win); + } + if (i == 256 + 0x57) { /* F11 */ + sheet_updown(shtctl->sheets[1], shtctl->top - 1); + } + if (i == 256 + 0xfa) { /*键盘成功接收到数据*/ + keycmd_wait = -1; + } + if (i == 256 + 0xfe) { /*键盘没有成功接收到数据*/ + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + } else if (512 <= i && i <= 767) { /* 鼠标数据*/ + if (mouse_decode(&mdec, i - 512) != 0) { + /* 已经收集了3字节的数据,移动光标 */ + mx += mdec.x; + my += mdec.y; + if (mx < 0) { + mx = 0; + } + if (my < 0) { + my = 0; + } + if (mx > binfo->scrnx - 1) { + mx = binfo->scrnx - 1; + } + if (my > binfo->scrny - 1) { + my = binfo->scrny - 1; + } + new_mx = mx; + new_my = my; + if ((mdec.btn & 0x01) != 0) { /* 按下左键 */ + if (mmx < 0) { + /*如果处于通常模式*/ + /*按照从上到下的顺序寻找鼠标所指向的图层*/ + for (j = shtctl->top - 1; j > 0; j--) { + sht = shtctl->sheets[j]; + x = mx - sht->vx0; + y = my - sht->vy0; + if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) { + if (sht->buf[y * sht->bxsize + x] != sht->col_inv) { + sheet_updown(sht, shtctl->top - 1); + if (sht != key_win) { + keywin_off(key_win); + key_win = sht; + keywin_on(key_win); + } + if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) { + mmx = mx; /*进入窗口移动模式*/ + mmy = my; + mmx2 = sht->vx0; + new_wy = sht->vy0; + } + if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <= y && y < 19) { + /*点击“×”按钮*/ + if ((sht->flags & 0x10) != 0) { /*该窗口是否为应用程序窗口?*/ + task = sht->task; + cons_putstr0(task->cons, "\nBreak(mouse) :\n"); + io_cli(); /*强制结束处理时禁止任务切换*/ + task->tss.eax = (int) &(task->tss.esp0); + task->tss.eip = (int) asm_end_app; + io_sti(); + task_run(task, -1, 0); + } else { /*命令行窗口*/ + task = sht->task; + sheet_updown(sht, -1); /*暂且隐藏该图层*/ + keywin_off(key_win); + key_win = shtctl->sheets[shtctl->top - 1]; + keywin_on(key_win); + io_cli(); + fifo32_put(&task->fifo, 4); + io_sti(); + } + } + break; + } + } + } + } else { + /*如果处于窗口移动模式*/ + x = mx - mmx; /*计算鼠标指针移动量*/ + y = my - mmy; + new_wx = (mmx2 + x + 2) & ~3; + new_wy = new_wy + y; + mmy = my; + } + } else { + /*没有按下左键*/ + mmx = -1; /*切换到一般模式*/ + if (new_wx != 0x7fffffff) { + sheet_slide(sht, new_wx, new_wy); /*固定图层位置*/ + new_wx = 0x7fffffff; + } + } + } + } else if (768 <= i && i <= 1023) { /*命令行窗口关闭处理*/ + close_console(shtctl->sheets0 + (i - 768)); + } else if (1024 <= i && i <= 2023) { + close_constask(taskctl->tasks0 + (i - 1024)); + } else if (2024 <= i && i <= 2279) { /*只关闭命令行窗口*/ + sht2 = shtctl->sheets0 + (i - 2024); + memman_free_4k(memman, (int) sht2->buf, 256 * 165); + sheet_free(sht2); + } + } + } +} + +void keywin_off(struct SHEET *key_win) +{ + change_wtitle8(key_win, 0); + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 3); /*命令行窗口光标OFF */ + } + return; +} + +void keywin_on(struct SHEET *key_win) +{ + change_wtitle8(key_win, 1); + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 2); /*命令行窗口光标ON */ + } + return; +} + +struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = task_alloc(); + int *cons_fifo = (int *) memman_alloc_4k(memman, 128 * 4); + task->cons_stack = memman_alloc_4k(memman, 64 * 1024); + task->tss.esp = task->cons_stack + 64 * 1024 - 12; + task->tss.eip = (int) &console_task; + task->tss.es = 1 * 8; + task->tss.cs = 2 * 8; + task->tss.ss = 1 * 8; + task->tss.ds = 1 * 8; + task->tss.fs = 1 * 8; + task->tss.gs = 1 * 8; + *((int *) (task->tss.esp + 4)) = (int) sht; + *((int *) (task->tss.esp + 8)) = memtotal; + task_run(task, 2, 2); /* level=2, priority=2 */ + fifo32_init(&task->fifo, 128, cons_fifo, task); + return task; +} + +struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct SHEET *sht = sheet_alloc(shtctl); + unsigned char *buf = (unsigned char *) memman_alloc_4k(memman, 256 * 165); + sheet_setbuf(sht, buf, 256, 165, -1); /*无透明色*/ + make_window8(buf, 256, 165, "console", 0); + make_textbox8(sht, 8, 28, 240, 128, COL8_000000); + sht->task = open_constask(sht, memtotal); + sht->flags |= 0x20; /*有光标*/ + return sht; +} + +void close_constask(struct TASK *task) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + task_sleep(task); + memman_free_4k(memman, task->cons_stack, 64 * 1024); + memman_free_4k(memman, (int) task->fifo.buf, 128 * 4); + task->flags = 0; /*用来替代task_free(task); */ + return; +} + +void close_console(struct SHEET *sht) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = sht->task; + memman_free_4k(memman, (int) sht->buf, 256 * 165); + sheet_free(sht); + close_constask(task); + return; +} diff --git a/29_day/haribote/bootpack.h b/29_day/haribote/bootpack.h new file mode 100644 index 0000000..f2e8243 --- /dev/null +++ b/29_day/haribote/bootpack.h @@ -0,0 +1,292 @@ +/* asmhead.nas */ +struct BOOTINFO { /* 0x0ff0-0x0fff */ + char cyls; /* 启动区读磁盘读到此为止 */ + char leds; /* 启动时键盘的LED的状态 */ + char vmode; /* 显卡模式为多少位彩色 */ + char reserve; + short scrnx, scrny; /* 画面分辨率 */ + char *vram; +}; +#define ADR_BOOTINFO 0x00000ff0 +#define ADR_DISKIMG 0x00100000 + +/* naskfunc.nas */ +void io_hlt(void); +void io_cli(void); +void io_sti(void); +void io_stihlt(void); +int io_in8(int port); +void io_out8(int port, int data); +int io_load_eflags(void); +void io_store_eflags(int eflags); +void load_gdtr(int limit, int addr); +void load_idtr(int limit, int addr); +int load_cr0(void); +void store_cr0(int cr0); +void load_tr(int tr); +void asm_inthandler0c(void); +void asm_inthandler0d(void); +void asm_inthandler20(void); +void asm_inthandler21(void); +void asm_inthandler2c(void); +unsigned int memtest_sub(unsigned int start, unsigned int end); +void farjmp(int eip, int cs); +void farcall(int eip, int cs); +void asm_hrb_api(void); +void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); +void asm_end_app(void); + +/* fifo.c */ +struct FIFO32 { + int *buf; + int p, q, size, free, flags; + struct TASK *task; +}; +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task); +int fifo32_put(struct FIFO32 *fifo, int data); +int fifo32_get(struct FIFO32 *fifo); +int fifo32_status(struct FIFO32 *fifo); + +/* graphic.c */ +void init_palette(void); +void set_palette(int start, int end, unsigned char *rgb); +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); +void init_screen8(char *vram, int x, int y); +void putfont8(char *vram, int xsize, int x, int y, char c, char *font); +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s); +void init_mouse_cursor8(char *mouse, char bc); +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize); +#define COL8_000000 0 +#define COL8_FF0000 1 +#define COL8_00FF00 2 +#define COL8_FFFF00 3 +#define COL8_0000FF 4 +#define COL8_FF00FF 5 +#define COL8_00FFFF 6 +#define COL8_FFFFFF 7 +#define COL8_C6C6C6 8 +#define COL8_840000 9 +#define COL8_008400 10 +#define COL8_848400 11 +#define COL8_000084 12 +#define COL8_840084 13 +#define COL8_008484 14 +#define COL8_848484 15 + +/* dsctbl.c */ +struct SEGMENT_DESCRIPTOR { + short limit_low, base_low; + char base_mid, access_right; + char limit_high, base_high; +}; +struct GATE_DESCRIPTOR { + short offset_low, selector; + char dw_count, access_right; + short offset_high; +}; +void init_gdtidt(void); +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar); +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar); +#define ADR_IDT 0x0026f800 +#define LIMIT_IDT 0x000007ff +#define ADR_GDT 0x00270000 +#define LIMIT_GDT 0x0000ffff +#define ADR_BOTPAK 0x00280000 +#define LIMIT_BOTPAK 0x0007ffff +#define AR_DATA32_RW 0x4092 +#define AR_CODE32_ER 0x409a +#define AR_LDT 0x0082 +#define AR_TSS32 0x0089 +#define AR_INTGATE32 0x008e + +/* int.c */ +void init_pic(void); +#define PIC0_ICW1 0x0020 +#define PIC0_OCW2 0x0020 +#define PIC0_IMR 0x0021 +#define PIC0_ICW2 0x0021 +#define PIC0_ICW3 0x0021 +#define PIC0_ICW4 0x0021 +#define PIC1_ICW1 0x00a0 +#define PIC1_OCW2 0x00a0 +#define PIC1_IMR 0x00a1 +#define PIC1_ICW2 0x00a1 +#define PIC1_ICW3 0x00a1 +#define PIC1_ICW4 0x00a1 + +/* keyboard.c */ +void inthandler21(int *esp); +void wait_KBC_sendready(void); +void init_keyboard(struct FIFO32 *fifo, int data0); +#define PORT_KEYDAT 0x0060 +#define PORT_KEYCMD 0x0064 + +/* mouse.c */ +struct MOUSE_DEC { + unsigned char buf[3], phase; + int x, y, btn; +}; +void inthandler2c(int *esp); +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec); +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat); + +/* memory.c */ +#define MEMMAN_FREES 4090 /* ����Ŗ�32KB */ +#define MEMMAN_ADDR 0x003c0000 +struct FREEINFO { /* ������� */ + unsigned int addr, size; +}; +struct MEMMAN { /* �������Ǘ� */ + int frees, maxfrees, lostsize, losts; + struct FREEINFO free[MEMMAN_FREES]; +}; +unsigned int memtest(unsigned int start, unsigned int end); +void memman_init(struct MEMMAN *man); +unsigned int memman_total(struct MEMMAN *man); +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size); +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size); +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size); +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size); + +/* sheet.c */ +#define MAX_SHEETS 256 +struct SHEET { + unsigned char *buf; + int bxsize, bysize, vx0, vy0, col_inv, height, flags; + struct SHTCTL *ctl; + struct TASK *task; +}; +struct SHTCTL { + unsigned char *vram, *map; + int xsize, ysize, top; + struct SHEET *sheets[MAX_SHEETS]; + struct SHEET sheets0[MAX_SHEETS]; +}; +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize); +struct SHEET *sheet_alloc(struct SHTCTL *ctl); +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv); +void sheet_updown(struct SHEET *sht, int height); +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1); +void sheet_slide(struct SHEET *sht, int vx0, int vy0); +void sheet_free(struct SHEET *sht); + +/* timer.c */ +#define MAX_TIMER 500 +struct TIMER { + struct TIMER *next; + unsigned int timeout; + char flags, flags2; + struct FIFO32 *fifo; + int data; +}; +struct TIMERCTL { + unsigned int count, next; + struct TIMER *t0; + struct TIMER timers0[MAX_TIMER]; +}; +extern struct TIMERCTL timerctl; +void init_pit(void); +struct TIMER *timer_alloc(void); +void timer_free(struct TIMER *timer); +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data); +void timer_settime(struct TIMER *timer, unsigned int timeout); +void inthandler20(int *esp); +int timer_cancel(struct TIMER *timer); +void timer_cancelall(struct FIFO32 *fifo); + +/* mtask.c */ +#define MAX_TASKS 1000 /*最大任务数量*/ +#define TASK_GDT0 3 /*定义从GDT的几号开始分配给TSS */ +#define MAX_TASKS_LV 100 +#define MAX_TASKLEVELS 10 +struct TSS32 { + int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3; + int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi; + int es, cs, ss, ds, fs, gs; + int ldtr, iomap; +}; +struct TASK { + int sel, flags; /* sel用来存放GDT的编号*/ + int level, priority; /* 优先级 */ + struct FIFO32 fifo; + struct TSS32 tss; + struct SEGMENT_DESCRIPTOR ldt[2]; + struct CONSOLE *cons; + int ds_base, cons_stack; + struct FILEHANDLE *fhandle; + int *fat; + char *cmdline; + unsigned char langmode, langbyte1; +}; +struct TASKLEVEL { + int running; /*正在运行的任务数量*/ + int now; /*这个变量用来记录当前正在运行的是哪个任务*/ + struct TASK *tasks[MAX_TASKS_LV]; +}; +struct TASKCTL { + int now_lv; /*现在活动中的LEVEL */ + char lv_change; /*在下次任务切换时是否需要改变LEVEL */ + struct TASKLEVEL level[MAX_TASKLEVELS]; + struct TASK tasks0[MAX_TASKS]; +}; +extern struct TASKCTL *taskctl; +extern struct TIMER *task_timer; +struct TASK *task_now(void); +struct TASK *task_init(struct MEMMAN *memman); +struct TASK *task_alloc(void); +void task_run(struct TASK *task, int level, int priority); +void task_switch(void); +void task_sleep(struct TASK *task); + +/* window.c */ +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act); +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l); +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c); +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act); +void change_wtitle8(struct SHEET *sht, char act); + +/* console.c */ +struct CONSOLE { + struct SHEET *sht; + int cur_x, cur_y, cur_c; + struct TIMER *timer; +}; +struct FILEHANDLE { + char *buf; + int size; + int pos; +}; +void console_task(struct SHEET *sheet, int memtotal); +void cons_putchar(struct CONSOLE *cons, int chr, char move); +void cons_newline(struct CONSOLE *cons); +void cons_putstr0(struct CONSOLE *cons, char *s); +void cons_putstr1(struct CONSOLE *cons, char *s, int l); +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal); +void cmd_mem(struct CONSOLE *cons, int memtotal); +void cmd_cls(struct CONSOLE *cons); +void cmd_dir(struct CONSOLE *cons); +void cmd_exit(struct CONSOLE *cons, int *fat); +void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal); +void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal); +void cmd_langmode(struct CONSOLE *cons, char *cmdline); +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline); +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax); +int *inthandler0d(int *esp); +int *inthandler0c(int *esp); +void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col); + +/* file.c */ +struct FILEINFO { + unsigned char name[8], ext[3], type; + char reserve[10]; + unsigned short time, date, clustno; + unsigned int size; +}; +void file_readfat(int *fat, unsigned char *img); +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img); +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max); + +/* bootpack.c */ +struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal); +struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal); diff --git a/29_day/haribote/console.c b/29_day/haribote/console.c new file mode 100644 index 0000000..b231d2b --- /dev/null +++ b/29_day/haribote/console.c @@ -0,0 +1,698 @@ +/* 命令行窗口相关 */ + +#include "bootpack.h" +#include +#include + +void console_task(struct SHEET *sheet, int memtotal) +{ + struct TASK *task = task_now(); + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + int i, *fat = (int *) memman_alloc_4k(memman, 4 * 2880); + struct FILEHANDLE fhandle[8]; + struct CONSOLE cons; + char cmdline[30]; + unsigned char *nihongo = (char *) *((int *) 0x0fe8); + + cons.sht = sheet; + cons.cur_x = 8; + cons.cur_y = 28; + cons.cur_c = -1; + task->cons = &cons; + task->cmdline = cmdline; + + if (cons.sht != 0) { + cons.timer = timer_alloc(); + timer_init(cons.timer, &task->fifo, 1); + timer_settime(cons.timer, 50); + } + file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); + for (i = 0; i < 8; i++) { + fhandle[i].buf = 0; /*未使用标记*/ + } + task->fhandle = fhandle; + task->fat = fat; + if (nihongo[4096] != 0xff) { /* 是否载入了字库?*/ + task->langmode = 1; + } else { + task->langmode = 0; + } + task->langbyte1 = 0; + + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + task_sleep(task); + io_sti(); + } else { + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1 && cons.sht != 0) { /*光标用定时器*/ + if (i != 0) { + timer_init(cons.timer, &task->fifo, 0); /*下次置0 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_FFFFFF; + } + } else { + timer_init(cons.timer, &task->fifo, 1); /*下次置1 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_000000; + } + } + timer_settime(cons.timer, 50); + } + if (i == 2) { /*光标ON */ + cons.cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + if (cons.sht != 0) { + boxfill8(cons.sht->buf, cons.sht->bxsize, COL8_000000, + cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + } + cons.cur_c = -1; + } + if (i == 4) { /*点击命令行窗口的“×”按钮*/ + cmd_exit(&cons, fat); + } + if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/ + if (i == 8 + 256) { + /*退格键*/ + if (cons.cur_x > 16) { + /*用空格擦除光标后将光标前移一位*/ + cons_putchar(&cons, ' ', 0); + cons.cur_x -= 8; + } + } else if (i == 10 + 256) { + /*回车键*/ + /*将光标用空格擦除后换行 */ + cons_putchar(&cons, ' ', 0); + cmdline[cons.cur_x / 8 - 2] = 0; + cons_newline(&cons); + cons_runcmd(cmdline, &cons, fat, memtotal); /*运行命令*/ + if (cons.sht == 0) { + cmd_exit(&cons, fat); + } + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + } else { + /*一般字符*/ + if (cons.cur_x < 240) { + /*显示一个字符之后将光标后移一位*/ + cmdline[cons.cur_x / 8 - 2] = i - 256; + cons_putchar(&cons, i - 256, 1); + } + } + } + /*重新显示光标*/ + if (cons.sht != 0) { + if (cons.cur_c >= 0) { + boxfill8(cons.sht->buf, cons.sht->bxsize, cons.cur_c, + cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + } + sheet_refresh(cons.sht, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16); + } + } + } +} + +void cons_putchar(struct CONSOLE *cons, int chr, char move) +{ + char s[2]; + s[0] = chr; + s[1] = 0; + if (s[0] == 0x09) { /*制表符*/ + for (;;) { + if (cons->sht != 0) { + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1); + } + cons->cur_x += 8; + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + if (((cons->cur_x - 8) & 0x1f) == 0) { + break; /*被32整除则break*/ + } + } + } else if (s[0] == 0x0a) { /*换行*/ + cons_newline(cons); + } else if (s[0] == 0x0d) { /*回车*/ + /*先不做任何操作*/ + } else { /*一般字符*/ + if (cons->sht != 0) { + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1); + } + if (move != 0) { + /* move为0时光标不后移*/ + cons->cur_x += 8; + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + } + } + return; +} + +void cons_newline(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + struct TASK *task = task_now(); + if (cons->cur_y < 28 + 112) { + cons->cur_y += 16; /*到下一行*/ + } else { + /*滚动*/ + if (sheet != 0) { + for (y = 28; y < 28 + 112; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize]; + } + } + for (y = 28 + 112; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + } + } + cons->cur_x = 8; + if (task->langmode == 1 && task->langbyte1 != 0) { + cons->cur_x += 8; + } + return; +} + +void cons_putstr0(struct CONSOLE *cons, char *s) +{ + for (; *s != 0; s++) { + cons_putchar(cons, *s, 1); + } + return; +} + +void cons_putstr1(struct CONSOLE *cons, char *s, int l) +{ + int i; + for (i = 0; i < l; i++) { + cons_putchar(cons, s[i], 1); + } + return; +} + +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) +{ + if (strcmp(cmdline, "mem") == 0 && cons->sht != 0) { + cmd_mem(cons, memtotal); + } else if (strcmp(cmdline, "cls") == 0 && cons->sht != 0) { + cmd_cls(cons); + } else if ((strcmp(cmdline, "dir") == 0 || strcmp(cmdline, "ls") == 0) && cons->sht != 0) { + cmd_dir(cons); + } else if (strcmp(cmdline, "exit") == 0) { + cmd_exit(cons, fat); + } else if (strncmp(cmdline, "start ", 6) == 0) { + cmd_start(cons, cmdline, memtotal); + } else if (strncmp(cmdline, "ncst ", 5) == 0) { + cmd_ncst(cons, cmdline, memtotal); + } else if (strncmp(cmdline, "langmode ", 9) == 0) { + cmd_langmode(cons, cmdline); + }else if (cmdline[0] != 0) { + if (cmd_app(cons, fat, cmdline) == 0) { + /*不是命令,不是应用程序,也不是空行*/ + cons_putstr0(cons, "Bad command.\n\n"); + } + } + return; +} + +void cmd_mem(struct CONSOLE *cons, int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + char s[60]; + sprintf(s, "total %dMB\nfree %dKB\n\n", memtotal / (1024 * 1024), memman_total(memman) / 1024); + cons_putstr0(cons, s); + return; +} + +void cmd_cls(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + for (y = 28; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + cons->cur_y = 28; + return; +} + +void cmd_dir(struct CONSOLE *cons) +{ + struct FILEINFO *finfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600); + int i, j; + char s[30]; + for (i = 0; i < 224; i++) { + if (finfo[i].name[0] == 0x00) { + break; + } + if (finfo[i].name[0] != 0xe5) { + if ((finfo[i].type & 0x18) == 0) { + sprintf(s, "filename.ext %7d\n", finfo[i].size); + for (j = 0; j < 8; j++) { + s[j] = finfo[i].name[j]; + } + s[ 9] = finfo[i].ext[0]; + s[10] = finfo[i].ext[1]; + s[11] = finfo[i].ext[2]; + cons_putstr0(cons, s); + } + } + } + cons_newline(cons); + return; +} + +void cmd_exit(struct CONSOLE *cons, int *fat) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = task_now(); + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct FIFO32 *fifo = (struct FIFO32 *) *((int *) 0x0fec); + if (cons->sht != 0) { + timer_cancel(cons->timer); + } + memman_free_4k(memman, (int) fat, 4 * 2880); + io_cli(); + if (cons->sht != 0) { + fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); /* 768〜1023 */ + } else { + fifo32_put(fifo, task - taskctl->tasks0 + 1024); /*1024~2023*/ + } + io_sti(); + for (;;) { + task_sleep(task); + } +} + +void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal) +{ + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct SHEET *sht = open_console(shtctl, memtotal); + struct FIFO32 *fifo = &sht->task->fifo; + int i; + sheet_slide(sht, 32, 4); + sheet_updown(sht, shtctl->top); + /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ + for (i = 6; cmdline[i] != 0; i++) { + fifo32_put(fifo, cmdline[i] + 256); + } + fifo32_put(fifo, 10 + 256); /*回车键*/ + cons_newline(cons); + return; +} + +void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal) +{ + struct TASK *task = open_constask(0, memtotal); + struct FIFO32 *fifo = &task->fifo; + int i; + + /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ + for (i = 5; cmdline[i] != 0; i++) { + fifo32_put(fifo, cmdline[i] + 256); + } + fifo32_put(fifo, 10 + 256); /*回车键*/ + cons_newline(cons); + return; +} + +void cmd_langmode(struct CONSOLE *cons, char *cmdline) +{ + struct TASK *task = task_now(); + unsigned char mode = cmdline[9] - '0'; + if (mode <= 2) { + task->langmode = mode; + } else { + cons_putstr0(cons, "mode number error.\n"); + } + cons_newline(cons); + return; +} + +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct FILEINFO *finfo; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + char name[18], *p, *q; + struct TASK *task = task_now(); + int i, segsiz, datsiz, esp, dathrb; + struct SHTCTL *shtctl; + struct SHEET *sht; + + /*根据命令行生成文件名*/ + for (i = 0; i < 13; i++) { + if (cmdline[i] <= ' ') { + break; + } + name[i] = cmdline[i]; + } + name[i] = 0; /*暂且将文件名的后面置为0*/ + + /*寻找文件 */ + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + if (finfo == 0 && name[i - 1] != '.') { + /*由于找不到文件,故在文件名后面加上“.hrb”后重新寻找*/ + name[i ] = '.'; + name[i + 1] = 'H'; + name[i + 2] = 'R'; + name[i + 3] = 'B'; + name[i + 4] = 0; + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + } + + if (finfo != 0) { + /*找到文件的情况*/ + p = (char *) memman_alloc_4k(memman, finfo->size); + file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); + if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) { + segsiz = *((int *) (p + 0x0000)); + esp = *((int *) (p + 0x000c)); + datsiz = *((int *) (p + 0x0010)); + dathrb = *((int *) (p + 0x0014)); + q = (char *) memman_alloc_4k(memman, segsiz); + task->ds_base = (int) q; + set_segmdesc(task->ldt + 0, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); + set_segmdesc(task->ldt + 1, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); + for (i = 0; i < datsiz; i++) { + q[esp + i] = p[dathrb + i]; + } + start_app(0x1b, 0 * 8 + 4, esp, 1 * 8 + 4, &(task->tss.esp0)); + shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + for (i = 0; i < MAX_SHEETS; i++) { + sht = &(shtctl->sheets0[i]); + if ((sht->flags & 0x11) == 0x11 && sht->task == task) { + /*找到被应用程序遗留的窗口*/ + sheet_free(sht); /*关闭*/ + } + } + for (i = 0; i < 8; i++) { /*将未关闭的文件关闭*/ + if (task->fhandle[i].buf != 0) { + memman_free_4k(memman, (int) task->fhandle[i].buf, task->fhandle[i].size); + task->fhandle[i].buf = 0; + } + } + timer_cancelall(&task->fifo); + memman_free_4k(memman, (int) q, segsiz); + task->langbyte1 = 0; + } else { + cons_putstr0(cons, ".hrb file format error.\n"); + } + memman_free_4k(memman, (int) p, finfo->size); + cons_newline(cons); + return 1; + } + /*没有找到文件的情况*/ + return 0; +} + +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) +{ + struct TASK *task = task_now(); + int ds_base = task->ds_base; + struct CONSOLE *cons = task->cons; + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct SHEET *sht; + struct FIFO32 *sys_fifo = (struct FIFO32 *) *((int *) 0x0fec); + int *reg = &eax + 1; /* eax后面的地址*/ + /*强行改写通过PUSHAD保存的值*/ + /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */ + /* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ + int i; + struct FILEINFO *finfo; + struct FILEHANDLE *fh; + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + + if (edx == 1) { + cons_putchar(cons, eax & 0xff, 1); + } else if (edx == 2) { + cons_putstr0(cons, (char *) ebx + ds_base); + } else if (edx == 3) { + cons_putstr1(cons, (char *) ebx + ds_base, ecx); + } else if (edx == 4) { + return &(task->tss.esp0); + } else if (edx == 5) { + sht = sheet_alloc(shtctl); + sht->task = task; + sht->flags |= 0x10; + sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax); + make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0); + sheet_slide(sht, ((shtctl->xsize - esi) / 2) & ~3, (shtctl->ysize - edi) / 2); + sheet_updown(sht, shtctl->top); /*将窗口图层高度指定为当前鼠标所在图层的高度,鼠标移到上层*/ + reg[7] = (int) sht; + } else if (edx == 6) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + putfonts8_asc(sht->buf, sht->bxsize, esi, edi, eax, (char *) ebp + ds_base); + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + ecx * 8, edi + 16); + } + } else if (edx == 7) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + boxfill8(sht->buf, sht->bxsize, ebp, eax, ecx, esi, edi); + if ((ebx & 1) == 0) { + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 8) { + memman_init((struct MEMMAN *) (ebx + ds_base)); + ecx &= 0xfffffff0; /*以16字节为单位*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 9) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + reg[7] = memman_alloc((struct MEMMAN *) (ebx + ds_base), ecx); + } else if (edx == 10) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 11) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + sht->buf[sht->bxsize * edi + esi] = eax; + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + 1, edi + 1); + } + } else if (edx == 12) { + sht = (struct SHEET *) ebx; + sheet_refresh(sht, eax, ecx, esi, edi); + } else if (edx == 13) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + hrb_api_linewin(sht, eax, ecx, esi, edi, ebp); + if ((ebx & 1) == 0) { + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 14) { + sheet_free((struct SHEET *) ebx); + } else if (edx == 15) { + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + if (eax != 0) { + task_sleep(task); /* FIFO为空,休眠并等待*/ + } else { + io_sti(); + reg[7] = -1; + return 0; + } + } + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1) { /*光标用定时器*/ + /*应用程序运行时不需要显示光标,因此总是将下次显示用的值置为1*/ + timer_init(cons->timer, &task->fifo, 1); /*下次置为1*/ + timer_settime(cons->timer, 50); + } + if (i == 2) { /*光标ON */ + cons->cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + cons->cur_c = -1; + } + if (i == 4) { /*只关闭命令行窗口*/ + timer_cancel(cons->timer); + io_cli(); + fifo32_put(sys_fifo, cons->sht - shtctl->sheets0 + 2024); /*2024~2279*/ + cons->sht = 0; + io_sti(); + } + if (i >= 256) { /*键盘数据(通过任务A)等*/ + reg[7] = i - 256; + return 0; + } + } + } else if (edx == 16) { + reg[7] = (int) timer_alloc(); + ((struct TIMER *) reg[7])->flags2 = 1; /*允许自动取消*/ + } else if (edx == 17) { + timer_init((struct TIMER *) ebx, &task->fifo, eax + 256); + } else if (edx == 18) { + timer_settime((struct TIMER *) ebx, eax); + } else if (edx == 19) { + timer_free((struct TIMER *) ebx); + } else if (edx == 20) { + if (eax == 0) { + i = io_in8(0x61); + io_out8(0x61, i & 0x0d); + } else { + i = 1193180000 / eax; + io_out8(0x43, 0xb6); + io_out8(0x42, i & 0xff); + io_out8(0x42, i >> 8); + i = io_in8(0x61); + io_out8(0x61, (i | 0x03) & 0x0f); + } + } else if (edx == 21) { + for (i = 0; i < 8; i++) { + if (task->fhandle[i].buf == 0) { + break; + } + } + fh = &task->fhandle[i]; + reg[7] = 0; + if (i < 8) { + finfo = file_search((char *) ebx + ds_base, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + if (finfo != 0) { + reg[7] = (int) fh; + fh->buf = (char *) memman_alloc_4k(memman, finfo->size); + fh->size = finfo->size; + fh->pos = 0; + file_loadfile(finfo->clustno, finfo->size, fh->buf, task->fat, (char *) (ADR_DISKIMG + 0x003e00)); + } + } + } else if (edx == 22) { + fh = (struct FILEHANDLE *) eax; + memman_free_4k(memman, (int) fh->buf, fh->size); + fh->buf = 0; + } else if (edx == 23) { + fh = (struct FILEHANDLE *) eax; + if (ecx == 0) { + fh->pos = ebx; + } else if (ecx == 1) { + fh->pos += ebx; + } else if (ecx == 2) { + fh->pos = fh->size + ebx; + } + if (fh->pos < 0) { + fh->pos = 0; + } + if (fh->pos > fh->size) { + fh->pos = fh->size; + } + } else if (edx == 24) { + fh = (struct FILEHANDLE *) eax; + if (ecx == 0) { + reg[7] = fh->size; + } else if (ecx == 1) { + reg[7] = fh->pos; + } else if (ecx == 2) { + reg[7] = fh->pos - fh->size; + } + } else if (edx == 25) { + fh = (struct FILEHANDLE *) eax; + for (i = 0; i < ecx; i++) { + if (fh->pos == fh->size) { + break; + } + *((char *) ebx + ds_base + i) = fh->buf[fh->pos]; + fh->pos++; + } + reg[7] = i; + } else if (edx == 26) { + i = 0; + for (;;) { + *((char *) ebx + ds_base + i) = task->cmdline[i]; + if (task->cmdline[i] == 0) { + break; + } + if (i >= ecx) { + break; + } + i++; + } + reg[7] = i; + } else if (edx == 27) { + reg[7] = task->langmode; + } + return 0; +} + +int *inthandler0c(int *esp) +{ + struct TASK *task = task_now(); + struct CONSOLE *cons = task->cons; + char s[30]; + cons_putstr0(cons, "\nINT 0C :\n Stack Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +int *inthandler0d(int *esp) +{ + struct TASK *task = task_now(); + struct CONSOLE *cons = task->cons; + char s[30]; + cons_putstr0(cons, "\nINT 0D :\n General Protected Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col) +{ + int i, x, y, len, dx, dy; + + dx = x1 - x0; + dy = y1 - y0; + x = x0 << 10; + y = y0 << 10; + if (dx < 0) { + dx = - dx; + } + if (dy < 0) { + dy = - dy; + } + if (dx >= dy) { + len = dx + 1; + if (x0 > x1) { + dx = -1024; + } else { + dx = 1024; + } + if (y0 <= y1) { + dy = ((y1 - y0 + 1) << 10) / len; + } else { + dy = ((y1 - y0 - 1) << 10) / len; + } + } else { + len = dy + 1; + if (y0 > y1) { + dy = -1024; + } else { + dy = 1024; + } + if (x0 <= x1) { + dx = ((x1 - x0 + 1) << 10) / len; + } else { + dx = ((x1 - x0 - 1) << 10) / len; + } + } + + for (i = 0; i < len; i++) { + sht->buf[(y >> 10) * sht->bxsize + (x >> 10)] = col; + x += dx; + y += dy; + } + + return; +} diff --git a/29_day/haribote/dsctbl.c b/29_day/haribote/dsctbl.c new file mode 100644 index 0000000..9ff2c67 --- /dev/null +++ b/29_day/haribote/dsctbl.c @@ -0,0 +1,59 @@ +/* GDT、IDT、descriptor table 关系处理 */ + +#include "bootpack.h" + +void init_gdtidt(void) +{ + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *) ADR_IDT; + int i; + + /* GDT初始化 */ + for (i = 0; i <= LIMIT_GDT / 8; i++) { + set_segmdesc(gdt + i, 0, 0, 0); + } + set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW); + set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER); + load_gdtr(LIMIT_GDT, ADR_GDT); + + /* IDT初始化 */ + for (i = 0; i <= LIMIT_IDT / 8; i++) { + set_gatedesc(idt + i, 0, 0, 0); + } + load_idtr(LIMIT_IDT, ADR_IDT); + + /* IDT设置*/ + set_gatedesc(idt + 0x0c, (int) asm_inthandler0c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x0d, (int) asm_inthandler0d, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x40, (int) asm_hrb_api, 2 * 8, AR_INTGATE32 + 0x60); + + return; +} + +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar) +{ + if (limit > 0xfffff) { + ar |= 0x8000; /* G_bit = 1 */ + limit /= 0x1000; + } + sd->limit_low = limit & 0xffff; + sd->base_low = base & 0xffff; + sd->base_mid = (base >> 16) & 0xff; + sd->access_right = ar & 0xff; + sd->limit_high = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0); + sd->base_high = (base >> 24) & 0xff; + return; +} + +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar) +{ + gd->offset_low = offset & 0xffff; + gd->selector = selector; + gd->dw_count = (ar >> 8) & 0xff; + gd->access_right = ar & 0xff; + gd->offset_high = (offset >> 16) & 0xffff; + return; +} diff --git a/29_day/haribote/fifo.c b/29_day/haribote/fifo.c new file mode 100644 index 0000000..8f28f4b --- /dev/null +++ b/29_day/haribote/fifo.c @@ -0,0 +1,63 @@ +/* FIFO */ + +#include "bootpack.h" + +#define FLAGS_OVERRUN 0x0001 + +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task) +/* FIFO缓冲区的初始化*/ +{ + fifo->size = size; + fifo->buf = buf; + fifo->free = size; /*空*/ + fifo->flags = 0; + fifo->p = 0; /*写入位置*/ + fifo->q = 0; /*读取位置*/ + fifo->task = task; /*有数据写入时需要唤醒的任务*/ + return; +} + +int fifo32_put(struct FIFO32 *fifo, int data) +/*向FIFO写入数据并累积起来*/ +{ + if (fifo->free == 0) { + /*没有空余空间,溢出*/ + fifo->flags |= FLAGS_OVERRUN; + return -1; + } + fifo->buf[fifo->p] = data; + fifo->p++; + if (fifo->p == fifo->size) { + fifo->p = 0; + } + fifo->free--; + if (fifo->task != 0) { + if (fifo->task->flags != 2) { /*如果任务处于休眠状态*/ + task_run(fifo->task, -1, 0); /*将任务唤醒*/ + } + } + return 0; +} + +int fifo32_get(struct FIFO32 *fifo) +/*从FIFO取得一个数据*/ +{ + int data; + if (fifo->free == fifo->size) { + /*当缓冲区为空的情况下返回-1*/ + return -1; + } + data = fifo->buf[fifo->q]; + fifo->q++; + if (fifo->q == fifo->size) { + fifo->q = 0; + } + fifo->free++; + return data; +} + +int fifo32_status(struct FIFO32 *fifo) +/*报告已经存储了多少数据*/ +{ + return fifo->size - fifo->free; +} diff --git a/29_day/haribote/file.c b/29_day/haribote/file.c new file mode 100644 index 0000000..bf9d063 --- /dev/null +++ b/29_day/haribote/file.c @@ -0,0 +1,74 @@ +/* 文件相关函数 */ + +#include "bootpack.h" + +void file_readfat(int *fat, unsigned char *img) +/*将磁盘映像中的FAT解压缩 */ +{ + int i, j = 0; + for (i = 0; i < 2880; i += 2) { + fat[i + 0] = (img[j + 0] | img[j + 1] << 8) & 0xfff; + fat[i + 1] = (img[j + 1] >> 4 | img[j + 2] << 4) & 0xfff; + j += 3; + } + return; +} + +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img) +{ + int i; + for (;;) { + if (size <= 512) { + for (i = 0; i < size; i++) { + buf[i] = img[clustno * 512 + i]; + } + break; + } + for (i = 0; i < 512; i++) { + buf[i] = img[clustno * 512 + i]; + } + size -= 512; + buf += 512; + clustno = fat[clustno]; + } + return; +} + +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max) +{ + int i, j; + char s[12]; + for (j = 0; j < 11; j++) { + s[j] = ' '; + } + j = 0; + for (i = 0; name[i] != 0; i++) { + if (j >= 11) { return 0; /*没有找到*/ } + if (name[i] == '.' && j <= 8) { + j = 8; + } else { + s[j] = name[i]; + if ('a' <= s[j] && s[j] <= 'z') { + /*将小写字母转换为大写字母*/ + s[j] -= 0x20; + } + j++; + } + } + for (i = 0; i < max; ) { + if (finfo->name[0] == 0x00) { + break; + } + if ((finfo[i].type & 0x18) == 0) { + for (j = 0; j < 11; j++) { + if (finfo[i].name[j] != s[j]) { + goto next; + } + } + return finfo + i; /*找到文件*/ + } +next: + i++; + } + return 0; /*没有找到*/ +} diff --git a/29_day/haribote/graphic.c b/29_day/haribote/graphic.c new file mode 100644 index 0000000..3ac5000 --- /dev/null +++ b/29_day/haribote/graphic.c @@ -0,0 +1,221 @@ +/* 关于绘图部分的处理 */ + +#include "bootpack.h" + +void init_palette(void) +{ + static unsigned char table_rgb[16 * 3] = { + 0x00, 0x00, 0x00, /* 0:黑 */ + 0xff, 0x00, 0x00, /* 1:梁红 */ + 0x00, 0xff, 0x00, /* 2:亮绿 */ + 0xff, 0xff, 0x00, /* 3:亮黄 */ + 0x00, 0x00, 0xff, /* 4:亮蓝 */ + 0xff, 0x00, 0xff, /* 5:亮紫 */ + 0x00, 0xff, 0xff, /* 6:浅亮蓝 */ + 0xff, 0xff, 0xff, /* 7:白 */ + 0xc6, 0xc6, 0xc6, /* 8:亮灰 */ + 0x84, 0x00, 0x00, /* 9:暗红 */ + 0x00, 0x84, 0x00, /* 10:暗绿 */ + 0x84, 0x84, 0x00, /* 11:暗黄 */ + 0x00, 0x00, 0x84, /* 12:暗青 */ + 0x84, 0x00, 0x84, /* 13:暗紫 */ + 0x00, 0x84, 0x84, /* 14:浅暗蓝 */ + 0x84, 0x84, 0x84 /* 15:暗灰 */ + }; + unsigned char table2[216 * 3]; + int r, g, b; + set_palette(0, 15, table_rgb); + for (b = 0; b < 6; b++) { + for (g = 0; g < 6; g++) { + for (r = 0; r < 6; r++) { + table2[(r + g * 6 + b * 36) * 3 + 0] = r * 51; + table2[(r + g * 6 + b * 36) * 3 + 1] = g * 51; + table2[(r + g * 6 + b * 36) * 3 + 2] = b * 51; + } + } + } + set_palette(16, 231, table2); + return; +} + +void set_palette(int start, int end, unsigned char *rgb) +{ + int i, eflags; + eflags = io_load_eflags(); /* 记录中断许可标志的值 */ + io_cli(); /* 将中断许可标志置为0,禁止中断 */ + io_out8(0x03c8, start); + for (i = start; i <= end; i++) { + io_out8(0x03c9, rgb[0] / 4); + io_out8(0x03c9, rgb[1] / 4); + io_out8(0x03c9, rgb[2] / 4); + rgb += 3; + } + io_store_eflags(eflags); /* 复原中断许可标志 */ + return; +} + +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) +{ + int x, y; + for (y = y0; y <= y1; y++) { + for (x = x0; x <= x1; x++) + vram[y * xsize + x] = c; + } + return; +} + +void init_screen8(char *vram, int x, int y) +{ + boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28); + boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1); + + boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24); + boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4); + boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4); + boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5); + boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3); + boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3); + + boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24); + boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4); + boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3); + boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3); + return; +} + +void putfont8(char *vram, int xsize, int x, int y, char c, char *font) +{ + int i; + char *p, d /* data */; + for (i = 0; i < 16; i++) { + p = vram + (y + i) * xsize + x; + d = font[i]; + if ((d & 0x80) != 0) { p[0] = c; } + if ((d & 0x40) != 0) { p[1] = c; } + if ((d & 0x20) != 0) { p[2] = c; } + if ((d & 0x10) != 0) { p[3] = c; } + if ((d & 0x08) != 0) { p[4] = c; } + if ((d & 0x04) != 0) { p[5] = c; } + if ((d & 0x02) != 0) { p[6] = c; } + if ((d & 0x01) != 0) { p[7] = c; } + } + return; +} + +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s) +{ + extern char hankaku[4096]; + struct TASK *task = task_now(); + char *nihongo = (char *) *((int *) 0x0fe8), *font; + int k, t; + + if (task->langmode == 0) { + for (; *s != 0x00; s++) { + putfont8(vram, xsize, x, y, c, hankaku + *s * 16); + x += 8; + } + } + if (task->langmode == 1) { + for (; *s != 0x00; s++) { + if (task->langbyte1 == 0) { + if ((0x81 <= *s && *s <= 0x9f) || (0xe0 <= *s && *s <= 0xfc)) { + task->langbyte1 = *s; + } else { + putfont8(vram, xsize, x, y, c, nihongo + *s * 16); + } + } else { + if (0x81 <= task->langbyte1 && task->langbyte1 <= 0x9f) { + k = (task->langbyte1 - 0x81) * 2; + } else { + k = (task->langbyte1 - 0xe0) * 2 + 62; + } + if (0x40 <= *s && *s <= 0x7e) { + t = *s - 0x40; + } else if (0x80 <= *s && *s <= 0x9e) { + t = *s - 0x80 + 63; + } else { + t = *s - 0x9f; + k++; + } + task->langbyte1 = 0; + font = nihongo + 256 * 16 + (k * 94 + t) * 32; + putfont8(vram, xsize, x - 8, y, c, font ); /* 左半部分 */ + putfont8(vram, xsize, x , y, c, font + 16); /* 右半部分 */ + } + x += 8; + } + } + if (task->langmode == 2) { + for (; *s != 0x00; s++) { + if (task->langbyte1 == 0) { + if (0x81 <= *s && *s <= 0xfe) { + task->langbyte1 = *s; + } else { + putfont8(vram, xsize, x, y, c, nihongo + *s * 16); + } + } else { + k = task->langbyte1 - 0xa1; + t = *s - 0xa1; + task->langbyte1 = 0; + font = nihongo + 256 * 16 + (k * 94 + t) * 32; + putfont8(vram, xsize, x - 8, y, c, font ); /* 左半部分 */ + putfont8(vram, xsize, x , y, c, font + 16); /* 右半部分 */ + } + x += 8; + } + } + return; +} + +void init_mouse_cursor8(char *mouse, char bc) +/* 鼠标的数据准备(16x16) */ +{ + static char cursor[16][16] = { + "**************..", + "*OOOOOOOOOOO*...", + "*OOOOOOOOOO*....", + "*OOOOOOOOO*.....", + "*OOOOOOOO*......", + "*OOOOOOO*.......", + "*OOOOOOO*.......", + "*OOOOOOOO*......", + "*OOOO**OOO*.....", + "*OOO*..*OOO*....", + "*OO*....*OOO*...", + "*O*......*OOO*..", + "**........*OOO*.", + "*..........*OOO*", + "............*OO*", + ".............***" + }; + int x, y; + + for (y = 0; y < 16; y++) { + for (x = 0; x < 16; x++) { + if (cursor[y][x] == '*') { + mouse[y * 16 + x] = COL8_000000; + } + if (cursor[y][x] == 'O') { + mouse[y * 16 + x] = COL8_FFFFFF; + } + if (cursor[y][x] == '.') { + mouse[y * 16 + x] = bc; + } + } + } + return; +} + +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize) +{ + int x, y; + for (y = 0; y < pysize; y++) { + for (x = 0; x < pxsize; x++) { + vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x]; + } + } + return; +} diff --git a/29_day/haribote/hankaku.txt b/29_day/haribote/hankaku.txt new file mode 100644 index 0000000..62d56f9 --- /dev/null +++ b/29_day/haribote/hankaku.txt @@ -0,0 +1,4609 @@ +OSASK̔ptHg𗬗p + +char 0x00 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x01 +........ +........ +..***... +.*...*.. +*.....*. +*.*.*.*. +*.*.*.*. +*.....*. +*.....*. +*.*.*.*. +*..*..*. +.*...*.. +..***... +........ +........ +........ + +char 0x02 +........ +........ +..***... +.*****.. +*******. +**.*.**. +**.*.**. +*******. +*******. +**.*.**. +***.***. +.*****.. +..***... +........ +........ +........ + +char 0x03 +........ +........ +........ +........ +.**.**.. +*******. +*******. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x04 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x05 +........ +........ +........ +........ +...*.... +..***... +.*.*.*.. +*******. +.*.*.*.. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x06 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +**.*.**. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x07 +........ +........ +........ +........ +........ +........ +...**... +..****.. +..****.. +...**... +........ +........ +........ +........ +........ +........ + +char 0x08 +******** +******** +******** +******** +******** +******** +***..*** +**....** +**....** +***..*** +******** +******** +******** +******** +******** +******** + +char 0x09 +........ +........ +........ +........ +........ +..****.. +.**..**. +.*....*. +.*....*. +.**..**. +..****.. +........ +........ +........ +........ +........ + +char 0x0a +******** +******** +******** +******** +******** +**....** +*..**..* +*.****.* +*.****.* +*..**..* +**....** +******** +******** +******** +******** +******** + +char 0x0b +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x0c +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ + +char 0x0d +........ +........ +....**.. +....***. +....*.** +....*.** +....*.*. +....*... +....*... +...**... +.****... +*****... +.***.... +........ +........ +........ + +char 0x0e +........ +........ +...***** +...***** +...*...* +...*...* +...*...* +...*...* +...*...* +...*...* +.***.*** +******** +.**..**. +........ +........ +........ + +char 0x0f +........ +........ +........ +........ +...*.... +.*.*.*.. +..***... +..*.*... +..***... +.*.*.*.. +...*.... +........ +........ +........ +........ +........ + +char 0x10 +........ +*....... +**...... +***..... +****.... +*****... +******.. +*******. +******.. +*****... +****.... +***..... +**...... +*....... +........ +........ + +char 0x11 +........ +......*. +.....**. +....***. +...****. +..*****. +.******. +*******. +.******. +..*****. +...****. +....***. +.....**. +......*. +........ +........ + +char 0x12 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ +........ + +char 0x13 +........ +........ +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +........ +........ +.*...*.. +.*...*.. +........ +........ + +char 0x14 +........ +..*****. +.*..*.*. +*...*.*. +*...*.*. +*...*.*. +*...*.*. +.*..*.*. +..***.*. +....*.*. +....*.*. +....*.*. +....*.*. +....*.*. +........ +........ + +char 0x15 +.*****.. +*.....*. +.*...... +..*..... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +....*... +.....*.. +*.....*. +.*****.. +........ + +char 0x16 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*******. +*******. +........ +........ + +char 0x17 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +.*****.. +........ +........ + +char 0x18 +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x19 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ + +char 0x1a +........ +........ +........ +........ +...*.... +....*... +.....*.. +*******. +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ + +char 0x1b +........ +........ +........ +........ +...*.... +..*..... +.*...... +*******. +.*...... +..*..... +...*.... +........ +........ +........ +........ +........ + +char 0x1c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*....... +*....... +*******. +........ +........ + +char 0x1d +........ +........ +........ +........ +........ +..*.*... +.*...*.. +*******. +.*...*.. +..*.*... +........ +........ +........ +........ +........ +........ + +char 0x1e +........ +........ +........ +........ +...*.... +...*.... +..***... +..***... +.*****.. +.*****.. +*******. +*******. +........ +........ +........ +........ + +char 0x1f +........ +........ +........ +........ +*******. +*******. +.*****.. +.*****.. +..***... +..***... +...*.... +...*.... +........ +........ +........ +........ + +char 0x20 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x21 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ +...*.... +...*.... +........ +........ + +char 0x22 +..*.*... +..*.*... +..*.*... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x23 +........ +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +........ +........ + +char 0x24 +...*.... +..***.*. +.*.*.**. +*..*..*. +*..*..*. +*..*.... +.*.*.... +..***... +...*.*.. +...*..*. +*..*..*. +*..*..*. +**.*.*.. +*.***... +...*.... +...*.... + +char 0x25 +.**...*. +*..*..*. +*..*.*.. +*..*.*.. +.**.*... +....*... +...*.... +...*.... +..*..... +..*.**.. +.*.*..*. +.*.*..*. +*..*..*. +*...**.. +........ +........ + +char 0x26 +........ +.***.... +*...*... +*...*... +*...*... +*..*.... +.**..... +.*...*** +*.*...*. +*..*..*. +*...*.*. +*....*.. +.*...**. +..***..* +........ +........ + +char 0x27 +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x28 +......*. +.....*.. +....*... +....*... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....*... +....*... +.....*.. +......*. +........ + +char 0x29 +*....... +.*...... +..*..... +..*..... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..*..... +..*..... +.*...... +*....... +........ + +char 0x2a +........ +........ +........ +........ +........ +...*.... +*..*..*. +.*.*.*.. +..***... +.*.*.*.. +*..*..*. +...*.... +........ +........ +........ +........ + +char 0x2b +........ +........ +........ +........ +........ +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ +........ +........ + +char 0x2c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x2d +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ +........ +........ +........ +........ +........ +........ + +char 0x2e +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x2f +......*. +......*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*...... +.*...... +*....... +*....... + +char 0x30 +........ +...**... +..*..*.. +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +...**... +........ +........ + +char 0x31 +........ +....*... +...**... +..*.*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +..*****. +........ +........ + +char 0x32 +........ +...**... +..*..*.. +.*....*. +.*....*. +......*. +.....*.. +....*... +...*.... +..*..... +..*..... +.*...... +.*...... +.******. +........ +........ + +char 0x33 +........ +...**... +..*..*.. +.*....*. +......*. +......*. +.....*.. +...**... +.....*.. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x34 +........ +....**.. +....**.. +....**.. +...*.*.. +...*.*.. +...*.*.. +..*..*.. +..*..*.. +.*...*.. +.******. +.....*.. +.....*.. +...****. +........ +........ + +char 0x35 +........ +.*****.. +.*...... +.*...... +.*...... +.*.**... +.**..*.. +......*. +......*. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x36 +........ +...**... +..*..*.. +.*....*. +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x37 +........ +.******. +.*....*. +.*....*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x38 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x39 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..**. +...**.*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x3a +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x3b +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x3c +........ +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +........ + +char 0x3d +........ +........ +........ +........ +........ +........ +*******. +........ +........ +*******. +........ +........ +........ +........ +........ +........ + +char 0x3e +........ +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +........ + +char 0x3f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.....*.. +....*... +...*.... +...*.... +........ +........ +...**... +...**... +........ +........ + +char 0x40 +........ +..***... +.*...*.. +*.....*. +*..**.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*..***.. +*....... +.*...**. +..***... +........ +........ + +char 0x41 +........ +...**... +...**... +...**... +...**... +..*..*.. +..*..*.. +..*..*.. +..*..*.. +.******. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x42 +........ +****.... +.*..*... +.*...*.. +.*...*.. +.*...*.. +.*..*... +.****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +*****... +........ +........ + +char 0x43 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*....... +*....... +*....... +*.....*. +.*....*. +.*...*.. +..***... +........ +........ + +char 0x44 +........ +*****... +.*...*.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...*.. +.*...*.. +*****... +........ +........ + +char 0x45 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x46 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...*.. +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x47 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*..****. +*.....*. +*.....*. +*.....*. +.*....*. +.*...**. +..***... +........ +........ + +char 0x48 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.******. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x49 +........ +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x4a +........ +...***** +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +*....*.. +.*..*... +..**.... +........ + +char 0x4b +........ +***..*** +.*....*. +.*...*.. +.*..*... +.*.*.... +.*.*.... +.**..... +.*.*.... +.*.*.... +.*..*... +.*...*.. +.*....*. +***..*** +........ +........ + +char 0x4c +........ +****.... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x4d +........ +**....** +.*....*. +.**..**. +.**..**. +.**..**. +.*.**.*. +.*.**.*. +.*.**.*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x4e +........ +**...*** +.*....*. +.**...*. +.**...*. +.*.*..*. +.*.*..*. +.*.*..*. +.*..*.*. +.*..*.*. +.*..*.*. +.*...**. +.*...**. +***...*. +........ +........ + +char 0x4f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x50 +........ +*****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +.****... +.*...... +.*...... +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x51 +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*..*..*. +*...*.*. +.*...*.. +..***.*. +........ +........ + +char 0x52 +........ +******.. +.*....*. +.*....*. +.*....*. +.*....*. +.*****.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x53 +........ +..***.*. +.*...**. +*.....*. +*.....*. +*....... +.*...... +..***... +.....*.. +......*. +*.....*. +*.....*. +**...*.. +*.***... +........ +........ + +char 0x54 +........ +*******. +*..*..*. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x55 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..****.. +........ +........ + +char 0x56 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...**... +...**... +........ +........ + +char 0x57 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x58 +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +..*..*.. +..*..*.. +..*..*.. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x59 +........ +***.***. +.*...*.. +.*...*.. +.*...*.. +..*.*... +..*.*... +..*.*... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x5a +........ +*******. +*....*.. +*....*.. +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*....*. +*.....*. +*******. +........ +........ + +char 0x5b +........ +..*****. +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*****. +........ + +char 0x5c +*....... +*....... +.*...... +.*...... +..*..... +..*..... +..*..... +...*.... +...*.... +....*... +....*... +.....*.. +.....*.. +.....*.. +......*. +......*. + +char 0x5d +........ +.*****.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.*****.. +........ + +char 0x5e +........ +...*.... +..*.*... +.*...*.. +*.....*. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x5f +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ + +char 0x60 +...*.... +....*... +.....*.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x61 +........ +........ +........ +........ +........ +.***.... +....*... +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +*...**.. +.***.**. +........ +........ + +char 0x62 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +........ +........ + +char 0x63 +........ +........ +........ +........ +........ +..**.... +.*..**.. +*....*.. +*....*.. +*....... +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x64 +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.**. +........ +........ + +char 0x65 +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +******.. +*....... +*.....*. +.*....*. +..****.. +........ +........ + +char 0x66 +....***. +...*.... +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x67 +........ +........ +........ +........ +........ +..**.**. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +.....*.. +.****... + +char 0x68 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x69 +........ +...*.... +...*.... +........ +........ +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6a +........ +.....*.. +.....*.. +........ +........ +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +....*... +....*... +..**.... + +char 0x6b +**...... +.*...... +.*...... +.*...... +.*...... +.*..***. +.*...*.. +.*..*... +.*.*.... +.**..... +.*.*.... +.*..*... +.*...*.. +***..**. +........ +........ + +char 0x6c +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6d +........ +........ +........ +........ +........ +****.**. +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +**.**.** +........ +........ + +char 0x6e +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x6f +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x70 +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +.*...... +***..... + +char 0x71 +........ +........ +........ +........ +........ +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +....***. + +char 0x72 +........ +........ +........ +........ +........ +**.***.. +.**...*. +.*....*. +.*...... +.*...... +.*...... +.*...... +.*...... +***..... +........ +........ + +char 0x73 +........ +........ +........ +........ +........ +.****.*. +*....**. +*.....*. +**...... +..***... +.....**. +*.....*. +**....*. +*.****.. +........ +........ + +char 0x74 +........ +........ +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....***. +........ +........ + +char 0x75 +........ +........ +........ +........ +........ +**...**. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...**. +..***.** +........ +........ + +char 0x76 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +........ +........ + +char 0x77 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x78 +........ +........ +........ +........ +........ +**...**. +.*...*.. +..*.*... +..*.*... +...*.... +..*.*... +..*.*... +.*...*.. +**...**. +........ +........ + +char 0x79 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...*.... +...*.... +.**..... + +char 0x7a +........ +........ +........ +........ +........ +*******. +*.....*. +*....*.. +....*... +...*.... +..*..... +.*....*. +*.....*. +*******. +........ +........ + +char 0x7b +........ +.....**. +....*... +...*.... +...*.... +...*.... +...*.... +.**..... +...*.... +...*.... +...*.... +...*.... +....*... +.....**. +........ +........ + +char 0x7c +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0x7d +........ +.**..... +...*.... +....*... +....*... +....*... +....*... +.....**. +....*... +....*... +....*... +....*... +...*.... +.**..... +........ +........ + +char 0x7e +........ +.***..*. +*...**.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x7f +........ +........ +........ +........ +...*.... +..*.*... +.*...*.. +*.....*. +*******. +*.....*. +*******. +........ +........ +........ +........ +........ + +char 0x80 +........ +..***... +.*...*.. +*.....*. +*....... +*....... +*....... +*....... +*....... +*....... +*....... +*.....*. +.*...*.. +..***... +...*.... +..*..... + +char 0x81 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x82 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x83 +........ +...*.... +..*.*... +.*...*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x84 +........ +........ +..*..*.. +..*..*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x85 +...*.... +....*... +.....*.. +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x86 +........ +...**... +..*..*.. +...**... +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x87 +........ +........ +........ +........ +........ +..****.. +.*....*. +*....... +*....... +*....... +*....... +*....... +.*....*. +..****.. +....*... +...*.... + +char 0x88 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x89 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8a +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8b +........ +........ +..*..*.. +..*..*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8c +........ +...*.... +..*.*... +.*...*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8d +...*.... +....*... +.....*.. +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8e +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x8f +........ +..***... +.*...*.. +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x90 +....**.. +....*... +...*.... +*******. +*....... +*....... +*....... +*....... +*****... +*....... +*....... +*....... +*....... +*******. +........ +........ + +char 0x91 +........ +........ +........ +........ +........ +.**..... +...***.. +...*..*. +.***..*. +*..****. +*..*.... +*..*.... +*..*..*. +.**.**.. +........ +........ + +char 0x92 +....**.. +...*.... +..*..... +..*.*... +..*.*... +..*.*... +*******. +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +........ +........ + +char 0x93 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x94 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x95 +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x96 +........ +...*.... +..*.*... +.*...*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x97 +...*.... +....*... +.....*.. +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x98 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +.*...*.. +.*...*.. +..*.*... +..*.*... +...*.... +...*.... +..*..... +..*..... +.*...... + +char 0x99 +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9a +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9b +........ +..*.*... +..*.*... +..*.*... +..****.. +.**.*.*. +*.*.*... +*.*.*... +*.*.*... +*.*.*... +*.*.*... +.**.*.*. +..****.. +..*.*... +..*.*... +..*.*... + +char 0x9c +........ +....**.. +...*..*. +..*..... +..*..... +..*..... +******.. +..*..... +..*..... +..*..... +.**..... +*.*..... +*.**..*. +.*..**.. +........ +........ + +char 0x9d +........ +*.....*. +*.....*. +.*...*.. +..*.*... +...*.... +*******. +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x9e +........ +***..... +*..*.... +*...*... +*...*... +*...*... +*..*.*.. +***..*.. +*..***** +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +........ +........ + +char 0x9f +........ +....**.. +...*..*. +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +...*.... +*..*.... +.**..... +........ +........ + +char 0xa0 +....**.. +....*... +...*.... +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0xa1 +....**.. +....*... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xa2 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa3 +....**.. +....*... +...*.... +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0xa4 +........ +...*..*. +..*.*.*. +..*..*.. +........ +*****... +*....*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0xa5 +...*..*. +..*.*.*. +..*..*.. +........ +*.....*. +**....*. +**....*. +*.*...*. +*..*..*. +*..*..*. +*...*.*. +*....**. +*....**. +*.....*. +........ +........ + +char 0xa6 +........ +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +*******. +........ +........ + +char 0xa7 +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +*******. +........ +........ + +char 0xa8 +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +..*..... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*....... +*....... +*....... +........ +........ + +char 0xaa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +......*. +......*. +......*. +........ +........ + +char 0xab +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +.****... +.....*.. +..***... +.*...... +.*****.. +........ +........ + +char 0xac +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +...**... +..*.*... +.*..*... +.*****.. +....*... +........ +........ + +char 0xad +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xae +........ +........ +........ +........ +...*..*. +..*..*.. +.*..*... +*..*.... +*..*.... +.*..*... +..*..*.. +...*..*. +........ +........ +........ +........ + +char 0xaf +........ +........ +........ +........ +*..*.... +.*..*... +..*..*.. +...*..*. +...*..*. +..*..*.. +.*..*... +*..*.... +........ +........ +........ +........ + +char 0xb0 +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. + +char 0xb1 +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. + +char 0xb2 +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* + +char 0xb3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb6 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb7 +........ +........ +........ +........ +........ +........ +........ +******.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb8 +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb9 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xba +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbb +........ +........ +........ +........ +........ +........ +........ +******.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +******.. +........ +........ +........ +........ +........ +........ + +char 0xbd +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******.. +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xbe +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +........ +........ +........ +........ +........ +........ + +char 0xbf +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc0 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc1 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc4 +........ +........ +........ +........ +........ +........ +........ +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc6 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xc8 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xc9 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xca +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xcb +........ +........ +........ +........ +........ +........ +........ +******** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcd +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xce +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcf +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xd0 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd1 +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd3 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xd5 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd6 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd8 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd9 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xda +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xdb +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdc +........ +........ +........ +........ +........ +........ +........ +........ +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdd +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... + +char 0xde +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** + +char 0xdf +******** +******** +******** +******** +******** +******** +******** +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xea +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xeb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xec +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xed +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xee +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xef +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfc +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfd +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfe +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xff +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ diff --git a/29_day/haribote/haribote.sys b/29_day/haribote/haribote.sys new file mode 100644 index 0000000000000000000000000000000000000000..e098d2b2dc72ce95ff296ef38e8f320f59a0abbd GIT binary patch literal 33331 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 + +void init_pic(void) +/* PIC初始化 */ +{ + io_out8(PIC0_IMR, 0xff ); /* 禁止所有中断 */ + io_out8(PIC1_IMR, 0xff ); /* 禁止所有中断 */ + + io_out8(PIC0_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC0_ICW2, 0x20 ); /* IRQ0-7由INT20-27接收 */ + io_out8(PIC0_ICW3, 1 << 2); /* PIC1由IRQ2相连 */ + io_out8(PIC0_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC1_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC1_ICW2, 0x28 ); /* IRQ8-15由INT28-2f接收 */ + io_out8(PIC1_ICW3, 2 ); /* PIC1由IRQ2连接 */ + io_out8(PIC1_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外全部禁止 */ + io_out8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中断 */ + + return; +} diff --git a/29_day/haribote/ipl10.nas b/29_day/haribote/ipl10.nas new file mode 100644 index 0000000..7108a21 --- /dev/null +++ b/29_day/haribote/ipl10.nas @@ -0,0 +1,109 @@ +; haribote-ipl +; TAB=4 + +CYLS EQU 10 ; 声明CYLS=10 + + ORG 0x7c00 ; 指明程序装载地址 + +; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code + + JMP entry + DB 0x90 + DB "HARIBOTE" ; 启动扇区名称(8字节) + DW 512 ; 每个扇区(sector)大小(必须512字节) + DB 1 ; 簇(cluster)大小(必须为1个扇区) + DW 1 ; FAT起始位置(一般为第一个扇区) + DB 2 ; FAT个数(必须为2) + DW 224 ; 根目录大小(一般为224项) + DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512) + DB 0xf0 ; 磁盘类型(必须为0xf0) + DW 9 ; FAT的长度(必??9扇区) + DW 18 ; 一个磁道(track)有几个扇区(必须为18) + DW 2 ; 磁头数(必??2) + DD 0 ; 不使用分区,必须是0 + DD 2880 ; 重写一次磁盘大小 + DB 0,0,0x29 ; 意义不明(固定) + DD 0xffffffff ; (可能是)卷标号码 + DB "HARIBOTEOS " ; 磁盘的名称(必须为11字?,不足填空格) + DB "FAT12 " ; 磁盘格式名称(必??8字?,不足填空格) + RESB 18 ; 先空出18字节 + +; 程序主体 + +entry: + MOV AX,0 ; 初始化寄存器 + MOV SS,AX + MOV SP,0x7c00 + MOV DS,AX + +; 读取磁盘 + + MOV AX,0x0820 + MOV ES,AX + MOV CH,0 ; 柱面0 + MOV DH,0 ; 磁头0 + MOV CL,2 ; 扇区2 + +readloop: + MOV SI,0 ; 记录失败次数寄存器 + +retry: + MOV AH,0x02 ; AH=0x02 : 读入磁盘 + MOV AL,1 ; 1个扇区 + MOV BX,0 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 调用磁盘BIOS + JNC next ; 没出错则跳转到fin + ADD SI,1 ; 往SI加1 + CMP SI,5 ; 比较SI与5 + JAE error ; SI >= 5 跳转到error + MOV AH,0x00 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 重置驱动器 + JMP retry +next: + MOV AX,ES ; 把内存地址后移0x200(512/16十六进制转换) + ADD AX,0x0020 + MOV ES,AX ; ADD ES,0x020因为没有ADD ES,只能通过AX进行 + ADD CL,1 ; 往CL里面加1 + CMP CL,18 ; 比较CL与18 + JBE readloop ; CL <= 18 跳转到readloop + MOV CL,1 + ADD DH,1 + CMP DH,2 + JB readloop ; DH < 2 跳转到readloop + MOV DH,0 + ADD CH,1 + CMP CH,CYLS + JB readloop ; CH < CYLS 跳转到readloop + +; 读取完毕,跳转到haribote.sys执行! + MOV [0x0ff0],CH ; IPLがどこまで読んだのかをメモ + JMP 0xc200 + +error: + MOV SI,msg + +putloop: + MOV AL,[SI] + ADD SI,1 ; 给SI加1 + CMP AL,0 + JE fin + MOV AH,0x0e ; 显示一个文字 + MOV BX,15 ; 指定字符颜色 + INT 0x10 ; 调用显卡BIOS + JMP putloop + +fin: + HLT ; 让CPU停止,等待指令 + JMP fin ; 无限循环 + +msg: + DB 0x0a, 0x0a ; 换行两次 + DB "load error" + DB 0x0a ; 换行 + DB 0 + + RESB 0x7dfe-$ ; 填写0x00直到0x001fe + + DB 0x55, 0xaa diff --git a/29_day/haribote/ipl20.nas b/29_day/haribote/ipl20.nas new file mode 100644 index 0000000..9b14835 --- /dev/null +++ b/29_day/haribote/ipl20.nas @@ -0,0 +1,109 @@ +; haribote-ipl +; TAB=4 + +CYLS EQU 20 ; 声明CYLS=20 + + ORG 0x7c00 ; 指明程序装载地址 + +; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code + + JMP entry + DB 0x90 + DB "HARIBOTE" ; 启动扇区名称(8字节) + DW 512 ; 每个扇区(sector)大小(必须512字节) + DB 1 ; 簇(cluster)大小(必须为1个扇区) + DW 1 ; FAT起始位置(一般为第一个扇区) + DB 2 ; FAT个数(必须为2) + DW 224 ; 根目录大小(一般为224项) + DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512) + DB 0xf0 ; 磁盘类型(必须为0xf0) + DW 9 ; FAT的长度(必??9扇区) + DW 18 ; 一个磁道(track)有几个扇区(必须为18) + DW 2 ; 磁头数(必??2) + DD 0 ; 不使用分区,必须是0 + DD 2880 ; 重写一次磁盘大小 + DB 0,0,0x29 ; 意义不明(固定) + DD 0xffffffff ; (可能是)卷标号码 + DB "HARIBOTEOS " ; 磁盘的名称(必须为11字?,不足填空格) + DB "FAT12 " ; 磁盘格式名称(必??8字?,不足填空格) + RESB 18 ; 先空出18字节 + +; 程序主体 + +entry: + MOV AX,0 ; 初始化寄存器 + MOV SS,AX + MOV SP,0x7c00 + MOV DS,AX + +; 读取磁盘 + + MOV AX,0x0820 + MOV ES,AX + MOV CH,0 ; 柱面0 + MOV DH,0 ; 磁头0 + MOV CL,2 ; 扇区2 + +readloop: + MOV SI,0 ; 记录失败次数寄存器 + +retry: + MOV AH,0x02 ; AH=0x02 : 读入磁盘 + MOV AL,1 ; 1个扇区 + MOV BX,0 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 调用磁盘BIOS + JNC next ; 没出错则跳转到fin + ADD SI,1 ; 往SI加1 + CMP SI,5 ; 比较SI与5 + JAE error ; SI >= 5 跳转到error + MOV AH,0x00 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 重置驱动器 + JMP retry +next: + MOV AX,ES ; 把内存地址后移0x200(512/16十六进制转换) + ADD AX,0x0020 + MOV ES,AX ; ADD ES,0x020因为没有ADD ES,只能通过AX进行 + ADD CL,1 ; 往CL里面加1 + CMP CL,18 ; 比较CL与18 + JBE readloop ; CL <= 18 跳转到readloop + MOV CL,1 + ADD DH,1 + CMP DH,2 + JB readloop ; DH < 2 跳转到readloop + MOV DH,0 + ADD CH,1 + CMP CH,CYLS + JB readloop ; CH < CYLS 跳转到readloop + +; 读取完毕,跳转到haribote.sys执行! + MOV [0x0ff0],CH ; IPLがどこまで読んだのかをメモ + JMP 0xc200 + +error: + MOV SI,msg + +putloop: + MOV AL,[SI] + ADD SI,1 ; 给SI加1 + CMP AL,0 + JE fin + MOV AH,0x0e ; 显示一个文字 + MOV BX,15 ; 指定字符颜色 + INT 0x10 ; 调用显卡BIOS + JMP putloop + +fin: + HLT ; 让CPU停止,等待指令 + JMP fin ; 无限循环 + +msg: + DB 0x0a, 0x0a ; 换行两次 + DB "load error" + DB 0x0a ; 换行 + DB 0 + + RESB 0x7dfe-$ ; 填写0x00直到0x001fe + + DB 0x55, 0xaa diff --git a/29_day/haribote/jp.nas b/29_day/haribote/jp.nas new file mode 100644 index 0000000..3f7cb00 --- /dev/null +++ b/29_day/haribote/jp.nas @@ -0,0 +1,107 @@ +; haribote-ipl +; TAB=4 + +CYLS EQU 10 ; ǂ܂œǂݍނ + + ORG 0x7c00 ; ̃vOǂɓǂݍ܂̂ + +; ȉ͕WIFAT12tH[}bgtbs[fBXN̂߂̋Lq + + JMP entry + DB 0x90 + DB "HARIBOTE" ; u[gZN^̖ORɏĂ悢i8oCgj + DW 512 ; 1ZN^̑傫i512ɂȂ΂Ȃj + DB 1 ; NX^̑傫i1ZN^ɂȂ΂Ȃj + DW 1 ; FATǂn܂邩iʂ1ZN^ڂɂj + DB 2 ; FAŤi2ɂȂ΂Ȃj + DW 224 ; [gfBNg̈̑傫iʂ224Ggɂj + DW 2880 ; ̃hCȗ傫i2880ZN^ɂȂ΂Ȃj + DB 0xf0 ; fBÃ^Cvi0xf0ɂȂ΂Ȃj + DW 9 ; FAT̈̒i9ZN^ɂȂ΂Ȃj + DW 18 ; 1gbNɂ‚̃ZN^邩i18ɂȂ΂Ȃj + DW 2 ; wbh̐i2ɂȂ΂Ȃj + DD 0 ; p[eBVgĂȂ̂ł͕K0 + DD 2880 ; ̃hCu傫x + DB 0,0,0x29 ; 悭킩Ȃǂ̒lɂĂƂ炵 + DD 0xffffffff ; Ԃ{[VAԍ + DB "HARIBOTEOS " ; fBXN̖Oi11oCgj + DB "FAT12 " ; tH[}bg̖Oi8oCgj + RESB 18 ; Ƃ肠18oCgĂ + +; vO{ + +entry: + MOV AX,0 ; WX^ + MOV SS,AX + MOV SP,0x7c00 + MOV DS,AX + +; fBXNǂ + + MOV AX,0x0820 + MOV ES,AX + MOV CH,0 ; V_0 + MOV DH,0 ; wbh0 + MOV CL,2 ; ZN^2 +readloop: + MOV SI,0 ; s񐔂𐔂郌WX^ +retry: + MOV AH,0x02 ; AH=0x02 : fBXNǂݍ + MOV AL,1 ; 1ZN^ + MOV BX,0 + MOV DL,0x00 ; AhCu + INT 0x13 ; fBXNBIOSĂяo + JNC next ; G[Ȃnext + ADD SI,1 ; SI1𑫂 + CMP SI,5 ; SI5r + JAE error ; SI >= 5 error + MOV AH,0x00 + MOV DL,0x00 ; AhCu + INT 0x13 ; hCũZbg + JMP retry +next: + MOV AX,ES ; AhX0x200i߂ + ADD AX,0x0020 + MOV ES,AX ; ADD ES,0x020 Ƃ߂Ȃ̂łĂ + ADD CL,1 ; CL1𑫂 + CMP CL,18 ; CL18r + JBE readloop ; CL <= 18 readloop + MOV CL,1 + ADD DH,1 + CMP DH,2 + JB readloop ; DH < 2 readloop + MOV DH,0 + ADD CH,1 + CMP CH,CYLS + JB readloop ; CH < CYLS readloop + +; ǂݏÎharibote.syssI + + MOV [0x0ff0],CH ; IPLǂ܂œǂ񂾂̂ + JMP 0xc200 + +error: + MOV AX,0 + MOV ES,AX + MOV SI,msg +putloop: + MOV AL,[SI] + ADD SI,1 ; SI1𑫂 + CMP AL,0 + JE fin + MOV AH,0x0e ; ꕶ\t@NV + MOV BX,15 ; J[R[h + INT 0x10 ; rfIBIOSĂяo + JMP putloop +fin: + HLT ; ܂CPU~ + JMP fin ; [v +msg: + DB 0x0a, 0x0a ; s2 + DB "load error" + DB 0x0a ; s + DB 0 + + RESB 0x7dfe-$ ; 0x7dfe܂ł0x00Ŗ߂閽 + + DB 0x55, 0xaa diff --git a/29_day/haribote/keyboard.c b/29_day/haribote/keyboard.c new file mode 100644 index 0000000..eb5140a --- /dev/null +++ b/29_day/haribote/keyboard.c @@ -0,0 +1,44 @@ +/* 键盘控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *keyfifo; +int keydata0; + +void inthandler21(int *esp) +{ + int data; + io_out8(PIC0_OCW2, 0x61); /* 把IRQ-01接收信号结束的信息通知给PIC */ + data = io_in8(PORT_KEYDAT); + fifo32_put(keyfifo, data + keydata0); + return; +} + +#define PORT_KEYSTA 0x0064 +#define KEYSTA_SEND_NOTREADY 0x02 +#define KEYCMD_WRITE_MODE 0x60 +#define KBC_MODE 0x47 + +void wait_KBC_sendready(void) +{ + /* 等待键盘控制电路准备完毕 */ + for (;;) { + if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) { + break; + } + } + return; +} + +void init_keyboard(struct FIFO32 *fifo, int data0) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + keyfifo = fifo; + keydata0 = data0; + /* 键盘控制器的初始化 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, KBC_MODE); + return; +} diff --git a/29_day/haribote/make.bat b/29_day/haribote/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/haribote/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/haribote/memory.c b/29_day/haribote/memory.c new file mode 100644 index 0000000..54a447a --- /dev/null +++ b/29_day/haribote/memory.c @@ -0,0 +1,162 @@ +/* �������֌W */ + +#include "bootpack.h" + +#define EFLAGS_AC_BIT 0x00040000 +#define CR0_CACHE_DISABLE 0x60000000 + +unsigned int memtest(unsigned int start, unsigned int end) +{ + char flg486 = 0; + unsigned int eflg, cr0, i; + + /* 确认CPU是386还是486以上的 */ + eflg = io_load_eflags(); + eflg |= EFLAGS_AC_BIT; /* AC-bit = 1 */ + io_store_eflags(eflg); + eflg = io_load_eflags(); + if ((eflg & EFLAGS_AC_BIT) != 0) { + /* 如果是386,即使设定AC=1,AC的值还会自动回到0 */ + flg486 = 1; + } + + eflg &= ~EFLAGS_AC_BIT; /* AC-bit = 0 */ + io_store_eflags(eflg); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 |= CR0_CACHE_DISABLE; /* 禁止缓存 */ + store_cr0(cr0); + } + + i = memtest_sub(start, end); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 &= ~CR0_CACHE_DISABLE; /* 允许缓存 */ + store_cr0(cr0); + } + + return i; +} + +void memman_init(struct MEMMAN *man) +{ + man->frees = 0; /* 可用信息数目 */ + man->maxfrees = 0; /* 用于观察可用状况:frees的最大值 */ + man->lostsize = 0; /* 释放失败的内存的大小总和 */ + man->losts = 0; /* 释放失败次数 */ + return; +} + +unsigned int memman_total(struct MEMMAN *man) +/* 报告空余内存大小的合计 */ +{ + unsigned int i, t = 0; + for (i = 0; i < man->frees; i++) { + t += man->free[i].size; + } + return t; +} + +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size) +/* 分配 */ +{ + unsigned int i, a; + for (i = 0; i < man->frees; i++) { + if (man->free[i].size >= size) { + /* 找到了足够大的内存 */ + a = man->free[i].addr; + man->free[i].addr += size; + man->free[i].size -= size; + if (man->free[i].size == 0) { + /* 如果free[i]变成了0,就减掉一条可用信息 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 代入结构体 */ + } + } + return a; + } + } + return 0; /* 没有可用空间 */ +} + +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size) +/* 释放 */ +{ + int i, j; + /* 为便于归纳内存,将free[]按照addr的顺序排列 */ + /* 所以,先决定应该放在哪里 */ + for (i = 0; i < man->frees; i++) { + if (man->free[i].addr > addr) { + break; + } + } + /* free[i - 1].addr < addr < free[i].addr */ + if (i > 0) { + /* 前面有可用内存 */ + if (man->free[i - 1].addr + man->free[i - 1].size == addr) { + /* 可以与前面的可用内存归纳到一起 */ + man->free[i - 1].size += size; + if (i < man->frees) { + /* 后面也有 */ + if (addr + size == man->free[i].addr) { + /* 也可以与后面的可用内存归纳到一起 */ + man->free[i - 1].size += man->free[i].size; + /* man->free[i]删除 */ + /* free[i]变成0后归纳到前面去 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 结构体赋值 */ + } + } + } + return 0; /* 成功完成 */ + } + } + /* 不能与前面的可用空间归纳到一起 */ + if (i < man->frees) { + /* 后面还有 */ + if (addr + size == man->free[i].addr) { + /* 可以与后面的内容归纳到一起 */ + man->free[i].addr = addr; + man->free[i].size += size; + return 0; /* 成功完成 */ + } + } + /* 既不能与前面归纳到一起,也不能与后面归纳到一起 */ + if (man->frees < MEMMAN_FREES) { + /* free[i]之后的,向后移动,腾出一点可用空间 */ + for (j = man->frees; j > i; j--) { + man->free[j] = man->free[j - 1]; + } + man->frees++; + if (man->maxfrees < man->frees) { + man->maxfrees = man->frees; /* 更新最大值 */ + } + man->free[i].addr = addr; + man->free[i].size = size; + return 0; /* 成功完成 */ + } + /* 不能往后移动 */ + man->losts++; + man->lostsize += size; + return -1; /* 失败 */ +} + +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size) +{ + unsigned int a; + size = (size + 0xfff) & 0xfffff000; + a = memman_alloc(man, size); + return a; +} + +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size) +{ + int i; + size = (size + 0xfff) & 0xfffff000; + i = memman_free(man, addr, size); + return i; +} diff --git a/29_day/haribote/mouse.c b/29_day/haribote/mouse.c new file mode 100644 index 0000000..0c6403e --- /dev/null +++ b/29_day/haribote/mouse.c @@ -0,0 +1,76 @@ +/* 鼠标控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *mousefifo; +int mousedata0; + +void inthandler2c(int *esp) +/* 来自PS/2鼠标的中断 */ +{ + int data; + io_out8(PIC1_OCW2, 0x64); /* 把IRQ-12接收信号结束的信息通知给PIC1 */ + io_out8(PIC0_OCW2, 0x62); /* 把IRQ-02接收信号结束的信息通知给PIC0 */ + data = io_in8(PORT_KEYDAT); + fifo32_put(mousefifo, data + mousedata0); + return; +} + +#define KEYCMD_SENDTO_MOUSE 0xd4 +#define MOUSECMD_ENABLE 0xf4 + +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + mousefifo = fifo; + mousedata0 = data0; + /* 鼠标有效 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, MOUSECMD_ENABLE); + /* 顺利的话,ACK(0xfa)会被发送*/ + mdec->phase = 0; /* 等待鼠标的0xfa的阶段*/ +return; +} + +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat) +{ + if (mdec->phase == 0) { + /* 等待鼠标的0xfa的阶段 */ + if (dat == 0xfa) { + mdec->phase = 1; + } + return 0; + } + if (mdec->phase == 1) { + /* 等待鼠标第一字节的阶段 */ + mdec->buf[0] = dat; + mdec->phase = 2; + return 0; + } + if (mdec->phase == 2) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[1] = dat; + mdec->phase = 3; + return 0; + } + if (mdec->phase == 3) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[2] = dat; + mdec->phase = 1; + mdec->btn = mdec->buf[0] & 0x07; + mdec->x = mdec->buf[1]; + mdec->y = mdec->buf[2]; + if ((mdec->buf[0] & 0x10) != 0) { + mdec->x |= 0xffffff00; + } + if ((mdec->buf[0] & 0x20) != 0) { + mdec->y |= 0xffffff00; + } + mdec->y = - mdec->y; /* 鼠标的y方向与画面符号相反 */ + return 1; + } + /* 应该不可能到这里来 */ + return -1; +} diff --git a/29_day/haribote/mtask.c b/29_day/haribote/mtask.c new file mode 100644 index 0000000..f67b935 --- /dev/null +++ b/29_day/haribote/mtask.c @@ -0,0 +1,203 @@ +/* 多任务管理 */ + +#include "bootpack.h" + +struct TASKCTL *taskctl; +struct TIMER *task_timer; + +struct TASK *task_now(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + return tl->tasks[tl->now]; +} + +void task_add(struct TASK *task) +{ + struct TASKLEVEL *tl = &taskctl->level[task->level]; + tl->tasks[tl->running] = task; + tl->running++; + task->flags = 2; /*活动中*/ + return; +} + +void task_remove(struct TASK *task) +{ + int i; + struct TASKLEVEL *tl = &taskctl->level[task->level]; + + /*寻找task所在的位置*/ + for (i = 0; i < tl->running; i++) { + if (tl->tasks[i] == task) { + /*在这里 */ + break; + } + } + + tl->running--; + if (i < tl->now) { + tl->now--; /*需要移动成员,要相应地处理 */ + } + if (tl->now >= tl->running) { + /*如果now的值出现异常,则进行修正*/ + tl->now = 0; + } + task->flags = 1; /* 休眠中 */ + + /* 移动 */ + for (; i < tl->running; i++) { + tl->tasks[i] = tl->tasks[i + 1]; + } + return; +} + +void task_switchsub(void) +{ + int i; + /*寻找最上层的LEVEL */ + for (i = 0; i < MAX_TASKLEVELS; i++) { + if (taskctl->level[i].running > 0) { + break; /*找到了*/ + } + } + taskctl->now_lv = i; + taskctl->lv_change = 0; + return; +} + +void task_idle(void) +{ + for (;;) { + io_hlt(); + } +} + +struct TASK *task_init(struct MEMMAN *memman) +{ + int i; + struct TASK *task, *idle; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + + + taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL)); + for (i = 0; i < MAX_TASKS; i++) { + taskctl->tasks0[i].flags = 0; + taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8; + taskctl->tasks0[i].tss.ldtr = (TASK_GDT0 + MAX_TASKS + i) * 8; + set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32); + set_segmdesc(gdt + TASK_GDT0 + MAX_TASKS + i, 15, (int) taskctl->tasks0[i].ldt, AR_LDT); + } + for (i = 0; i < MAX_TASKLEVELS; i++) { + taskctl->level[i].running = 0; + taskctl->level[i].now = 0; + } + + task = task_alloc(); + task->flags = 2; /*活动中标志*/ + task->priority = 2; /* 0.02秒*/ + task->level = 0; /*最高LEVEL */ + task_add(task); + task_switchsub(); /* LEVEL 设置*/ + load_tr(task->sel); + task_timer = timer_alloc(); + timer_settime(task_timer, task->priority); + + idle = task_alloc(); + idle->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024; + idle->tss.eip = (int) &task_idle; + idle->tss.es = 1 * 8; + idle->tss.cs = 2 * 8; + idle->tss.ss = 1 * 8; + idle->tss.ds = 1 * 8; + idle->tss.fs = 1 * 8; + idle->tss.gs = 1 * 8; + task_run(idle, MAX_TASKLEVELS - 1, 1); + + return task; +} + +struct TASK *task_alloc(void) +{ + int i; + struct TASK *task; + for (i = 0; i < MAX_TASKS; i++) { + if (taskctl->tasks0[i].flags == 0) { + task = &taskctl->tasks0[i]; + task->flags = 1; /*正在使用的标志*/ + task->tss.eflags = 0x00000202; /* IF = 1; */ + task->tss.eax = 0; /*这里先置为0*/ + task->tss.ecx = 0; + task->tss.edx = 0; + task->tss.ebx = 0; + task->tss.ebp = 0; + task->tss.esi = 0; + task->tss.edi = 0; + task->tss.es = 0; + task->tss.ds = 0; + task->tss.fs = 0; + task->tss.gs = 0; + task->tss.iomap = 0x40000000; + task->tss.ss0 = 0; + return task; + } + } + return 0; /*全部正在使用*/ +} + +void task_run(struct TASK *task, int level, int priority) +{ + if (level < 0) { + level = task->level; /*不改变LEVEL */ + } + if (priority > 0) { + task->priority = priority; + } + if (task->flags == 2 && task->level != level) { + /*改变活动中的LEVEL */ + task_remove(task); /*这里执行之后flag的值会变为1,于是下面的if语句块也会被执行*/ + } + if (task->flags != 2) { + /*从休眠状态唤醒的情形*/ + task->level = level; + task_add(task); + } + taskctl->lv_change = 1; /*下次任务切换时检查LEVEL */ + return; +} + +void task_sleep(struct TASK *task) +{ + struct TASK *now_task; + if (task->flags == 2) { + /*如果处于活动状态*/ + now_task = task_now(); + task_remove(task); /*执行此语句的话flags将变为1 */ + if (task == now_task) { + /*如果是让自己休眠,则需要进行任务切换*/ + task_switchsub(); + now_task = task_now(); /*在设定后获取当前任务的值*/ + farjmp(0, now_task->sel); + } + } + return; +} + + +void task_switch(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + struct TASK *new_task, *now_task = tl->tasks[tl->now]; + tl->now++; + if (tl->now == tl->running) { + tl->now = 0; + } + if (taskctl->lv_change != 0) { + task_switchsub(); + tl = &taskctl->level[taskctl->now_lv]; + } + new_task = tl->tasks[tl->now]; + timer_settime(task_timer, new_task->priority); + if (new_task != now_task) { + farjmp(0, new_task->sel); + } + return; +} diff --git a/29_day/haribote/naskfunc.nas b/29_day/haribote/naskfunc.nas new file mode 100644 index 0000000..a45775d --- /dev/null +++ b/29_day/haribote/naskfunc.nas @@ -0,0 +1,291 @@ +; naskfunc +; TAB=4 + +[FORMAT "WCOFF"] ; 制作目标文件的模式 +[INSTRSET "i486p"] ; 使用到486为止的指令 +[BITS 32] ; 3制作32位模式用的机器语言 +[FILE "naskfunc.nas"] ; 文件名 + + GLOBAL _io_hlt, _io_cli, _io_sti, _io_stihlt + GLOBAL _io_in8, _io_in16, _io_in32 + GLOBAL _io_out8, _io_out16, _io_out32 + GLOBAL _io_load_eflags, _io_store_eflags + GLOBAL _load_gdtr, _load_idtr + GLOBAL _load_cr0, _store_cr0 + GLOBAL _load_tr + GLOBAL _asm_inthandler20, _asm_inthandler21 + GLOBAL _asm_inthandler2c, _asm_inthandler0c + GLOBAL _asm_inthandler0d, _asm_end_app + GLOBAL _memtest_sub + GLOBAL _farjmp, _farcall + GLOBAL _asm_hrb_api, _start_app + EXTERN _inthandler20, _inthandler21 + EXTERN _inthandler2c, _inthandler0d + EXTERN _inthandler0c + EXTERN _hrb_api + +[SECTION .text] + +_io_hlt: ; void io_hlt(void); + HLT + RET + +_io_cli: ; void io_cli(void); + CLI + RET + +_io_sti: ; void io_sti(void); + STI + RET + +_io_stihlt: ; void io_stihlt(void); + STI + HLT + RET + +_io_in8: ; int io_in8(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AL,DX + RET + +_io_in16: ; int io_in16(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AX,DX + RET + +_io_in32: ; int io_in32(int port); + MOV EDX,[ESP+4] ; port + IN EAX,DX + RET + +_io_out8: ; void io_out8(int port, int data); + MOV EDX,[ESP+4] ; port + MOV AL,[ESP+8] ; data + OUT DX,AL + RET + +_io_out16: ; void io_out16(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,AX + RET + +_io_out32: ; void io_out32(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,EAX + RET + +_io_load_eflags: ; int io_load_eflags(void); + PUSHFD ; PUSH EFLAGS + POP EAX + RET + +_io_store_eflags: ; void io_store_eflags(int eflags); + MOV EAX,[ESP+4] + PUSH EAX + POPFD ; POP EFLAGS + RET + +_load_gdtr: ; void load_gdtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LGDT [ESP+6] + RET + +_load_idtr: ; void load_idtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LIDT [ESP+6] + RET + +_load_cr0: ; int load_cr0(void); + MOV EAX,CR0 + RET + +_store_cr0: ; void store_cr0(int cr0); + MOV EAX,[ESP+4] + MOV CR0,EAX + RET + +_load_tr: ; void load_tr(int tr); + LTR [ESP+4] ; tr + RET + +_asm_inthandler20: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler20 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler21: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler21 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler2c: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler2c + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler0c: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0c + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; 在INT 0x0c中也需要这句 + IRETD + +_asm_inthandler0d: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0d + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; INT 0x0d需要这句 + IRETD + +_memtest_sub: ; unsigned int memtest_sub(unsigned int start, unsigned int end) + PUSH EDI ; (由于还要使用EBX, ESI, EDI) + PUSH ESI + PUSH EBX + MOV ESI,0xaa55aa55 ; pat0 = 0xaa55aa55; + MOV EDI,0x55aa55aa ; pat1 = 0x55aa55aa; + MOV EAX,[ESP+12+4] ; i = start; +mts_loop: + MOV EBX,EAX + ADD EBX,0xffc ; p = i + 0xffc; + MOV EDX,[EBX] ; old = *p; + MOV [EBX],ESI ; *p = pat0; + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP EDI,[EBX] ; if (*p != pat1) goto fin; + JNE mts_fin + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP ESI,[EBX] ; if (*p != pat0) goto fin; + JNE mts_fin + MOV [EBX],EDX ; *p = old; + ADD EAX,0x1000 ; i += 0x1000; + CMP EAX,[ESP+12+8] ; if (i <= end) goto mts_loop; + JBE mts_loop + POP EBX + POP ESI + POP EDI + RET +mts_fin: + MOV [EBX],EDX ; *p = old; + POP EBX + POP ESI + POP EDI + RET + +_farjmp: ; void farjmp(int eip, int cs); + JMP FAR [ESP+4] ; eip, cs + RET + +_farcall: ; void farcall(int eip, int cs); + CALL FAR [ESP+4] ; eip, cs + RET + +_asm_hrb_api: + STI + PUSH DS + PUSH ES + PUSHAD ; 用于保存的PUSH + PUSHAD ; 用于向hrb_api传值的PUSH + MOV AX,SS + MOV DS,AX ; 将操作系统用段地址存入DS和ES + MOV ES,AX + CALL _hrb_api + CMP EAX,0 ; 当EAX不为0时程序结束 + JNE _asm_end_app + ADD ESP,32 + POPAD + POP ES + POP DS + IRETD +_asm_end_app: +; EAX为tss.esp0的地址 + MOV ESP,[EAX] + MOV DWORD [EAX+4],0 + POPAD + RET ; 返回cmd_app + +_start_app: ; void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); + PUSHAD ; 将32位寄存器的值全部保存起来 + MOV EAX,[ESP+36] ; 应用程序用EIP + MOV ECX,[ESP+40] ; 应用程序用CS + MOV EDX,[ESP+44] ; 应用程序用ESP + MOV EBX,[ESP+48] ; 应用程序用DS/SS + MOV EBP,[ESP+52] ; tss.esp0的地址 + MOV [EBP ],ESP ; 保存操作系统用ESP + MOV [EBP+4],SS ; 保存操作系统用SS + MOV ES,BX + MOV DS,BX + MOV FS,BX + MOV GS,BX +; 下面调整栈,以免用RETF跳转到应用程序 + OR ECX,3 ; 将应用程序用段号和3进行OR运算 + OR EBX,3 ; 将应用程序用段号和3进行OR运算 + PUSH EBX ; 应用程序的SS + PUSH EDX ; 应用程序的ESP + PUSH ECX ; 应用程序的CS + PUSH EAX ; 应用程序的EIP + RETF +; 应用程序结束后不会回到这里 diff --git a/29_day/haribote/sheet.c b/29_day/haribote/sheet.c new file mode 100644 index 0000000..14aa0ea --- /dev/null +++ b/29_day/haribote/sheet.c @@ -0,0 +1,294 @@ +/* sheet */ + +#include "bootpack.h" + +#define SHEET_USE 1 + +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize) +{ + struct SHTCTL *ctl; + int i; + ctl = (struct SHTCTL *) memman_alloc_4k(memman, sizeof (struct SHTCTL)); + if (ctl == 0) { + goto err; + } + ctl->map = (unsigned char *) memman_alloc_4k(memman, xsize * ysize); + if (ctl->map == 0) { + memman_free_4k(memman, (int) ctl, sizeof (struct SHTCTL)); + goto err; + } + ctl->vram = vram; + ctl->xsize = xsize; + ctl->ysize = ysize; + ctl->top = -1; /* 没有一张SHEET */ + for (i = 0; i < MAX_SHEETS; i++) { + ctl->sheets0[i].flags = 0; /* 标记为未使用 */ + ctl->sheets0[i].ctl = ctl; /* 记录所属*/ + } +err: + return ctl; +} + +struct SHEET *sheet_alloc(struct SHTCTL *ctl) +{ + struct SHEET *sht; + int i; + for (i = 0; i < MAX_SHEETS; i++) { + if (ctl->sheets0[i].flags == 0) { + sht = &ctl->sheets0[i]; + sht->flags = SHEET_USE; /* 标记为正在使用*/ + sht->height = -1; /* 隐藏 */ + sht->task = 0; /*不使用自动关闭功能*/ + return sht; + } + } + return 0; /* 所有的SHEET都处于正在使用状态*/ +} + +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv) +{ + sht->buf = buf; + sht->bxsize = xsize; + sht->bysize = ysize; + sht->col_inv = col_inv; + return; +} + +void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1, sid4, *p;; + unsigned char *buf, sid, *map = ctl->map; + struct SHEET *sht; + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= ctl->top; h++) { + sht = ctl->sheets[h]; + sid = sht - ctl->sheets0; /* 将进行了减法计算的地址作为图层号码使用 */ + buf = sht->buf; + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } + if (by1 > sht->bysize) { by1 = sht->bysize; } + if (sht->col_inv == -1) { + if ((sht->vx0 & 3) == 0 && (bx0 & 3) == 0 && (bx1 & 3) == 0) { + /*无透明色图层专用的高速版(4字节型)*/ + bx1 = (bx1 - bx0) / 4; /* MOV次数*/ + sid4 = sid | sid << 8 | sid << 16 | sid << 24; + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + vx = sht->vx0 + bx0; + p = (int *) &map[vy * ctl->xsize + vx]; + for (bx = 0; bx < bx1; bx++) { + p[bx] = sid4; + } + } + } else { + /*无透明色图层专用的高速版(1字节型)*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + map[vy * ctl->xsize + vx] = sid; + } + } + } + } else { + /*有透明色图层用的普通版*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (buf[by * sht->bxsize + bx] != sht->col_inv) { + map[vy * ctl->xsize + vx] = sid; + } + } + } + } + } + return; +} + +void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0, int h1) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1, bx2, sid4, i, i1, *p, *q, *r; + unsigned char *buf, *vram = ctl->vram, *map = ctl->map, sid; + struct SHEET *sht; + + /* 如果refresh的范围超出了画面则修正 */ + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= h1; h++) { + sht = ctl->sheets[h]; + buf = sht->buf; + sid = sht - ctl->sheets0; + + /* 使用vx0~vy1,对bx0~by1进行倒推 */ + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } /* 处理刷新范围在图层外侧 */ + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } /* 应对不同的重叠方式 */ + if (by1 > sht->bysize) { by1 = sht->bysize; } + if ((sht->vx0 & 3) == 0) { + /* 4字节型*/ + i = (bx0 + 3) / 4; /* bx0除以4(小数进位)*/ + i1 = bx1 / 4; /* bx1除以4(小数舍去)*/ + i1 = i1 - i; + sid4 = sid | sid << 8 | sid << 16 | sid << 24; + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1 && (bx & 3) != 0; bx++) { + /*前面被4除多余的部分逐个字节写入*/ + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + vx = sht->vx0 + bx; + p = (int *) &map[vy * ctl->xsize + vx]; + q = (int *) &vram[vy * ctl->xsize + vx]; + r = (int *) &buf[by * sht->bxsize + bx]; + for (i = 0; i < i1; i++) { + /* 4的倍数部分*/ + if (p[i] == sid4) { + q[i] = r[i]; /*估计大多数会是这种情况,因此速度会变快*/ + } else { + bx2 = bx + i * 4; + vx = sht->vx0 + bx2; + if (map[vy * ctl->xsize + vx + 0] == sid) { + vram[vy * ctl->xsize + vx + 0] = buf[by * sht->bxsize + bx2 + 0]; + } + if (map[vy * ctl->xsize + vx + 1] == sid) { + vram[vy * ctl->xsize + vx + 1] = buf[by * sht->bxsize + bx2 + 1]; + } + if (map[vy * ctl->xsize + vx + 2] == sid) { + vram[vy * ctl->xsize + vx + 2] = buf[by * sht->bxsize + bx2 + 2]; + } + if (map[vy * ctl->xsize + vx + 3] == sid) { + vram[vy * ctl->xsize + vx + 3] = buf[by * sht->bxsize + bx2 + 3]; + } + } + } + for (bx += i1 * 4; bx < bx1; bx++) { + /*后面被4除多余的部分逐个字节写入*/ + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + } + } else { + /* 1字节型*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + } + } + } + return; +} + +void sheet_updown(struct SHEET *sht, int height) +{ + struct SHTCTL *ctl = sht->ctl; + int h, old = sht->height; /* 存储设置前的高度信息 */ + if (height > ctl->top + 1) { + height = ctl->top + 1; + } + if (height < -1) { + height = -1; + } + sht->height = height;/* 设定高度 */ + + /* 下面主要是进行sheets[]的重新排列 */ + if (old > height) { /* 比以前低 */ + if (height >= 0) { + /* 把中间的往上提 */ + for (h = old; h > height; h--) { + ctl->sheets[h] = ctl->sheets[h - 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1, old); + } else { /* 隐藏 */ + if (ctl->top > old) { + /* 把上面的降下来 */ + for (h = old; h < ctl->top; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + } + ctl->top--; /* 由于显示中的图层减少了一个,所以最上面的图层高度下降 */ + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0, old - 1); + } + } else if (old < height) { /* 比以前高 */ + if (old >= 0) { + /* 把中间的拉下去 */ + for (h = old; h < height; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + } else { /* 由隐藏状态转为显示状态 */ + /* 将已在上面的提上来 */ + for (h = ctl->top; h >= height; h--) { + ctl->sheets[h + 1] = ctl->sheets[h]; + ctl->sheets[h + 1]->height = h + 1; + } + ctl->sheets[height] = sht; + ctl->top++; /* 由于已显示的图层增加了1个,所以最上面的图层高度增加 */ + } + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height, height); /* 按新图层信息重新绘制画面 */ + } + return; +} + +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1) +{ + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面*/ + sheet_refreshsub(sht->ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1, sht->height, sht->height); + } + return; +} + +void sheet_slide(struct SHEET *sht, int vx0, int vy0) +{ + struct SHTCTL *ctl = sht->ctl; + int old_vx0 = sht->vx0, old_vy0 = sht->vy0; + sht->vx0 = vx0; + sht->vy0 = vy0; + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面 */ + sheet_refreshmap(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0); + sheet_refreshmap(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height); + sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0, sht->height - 1); + sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height, sht->height); + } + return; +} + +void sheet_free(struct SHEET *sht) +{ + if (sht->height >= 0) { + sheet_updown(sht, -1); /* 如果处于显示状态,则先设定为隐藏 */ + } + sht->flags = 0; /* "未使用"标志 */ + return; +} diff --git a/29_day/haribote/timer.c b/29_day/haribote/timer.c new file mode 100644 index 0000000..9018ac8 --- /dev/null +++ b/29_day/haribote/timer.c @@ -0,0 +1,169 @@ +/* 定时器 */ + +#include "bootpack.h" + +#define PIT_CTRL 0x0043 +#define PIT_CNT0 0x0040 + +struct TIMERCTL timerctl; + +#define TIMER_FLAGS_ALLOC 1 /* 已配置状态 */ +#define TIMER_FLAGS_USING 2 /* 定时器运行中 */ + +void init_pit(void) +{ + int i; + struct TIMER *t; + io_out8(PIT_CTRL, 0x34); + io_out8(PIT_CNT0, 0x9c); + io_out8(PIT_CNT0, 0x2e); + timerctl.count = 0; + for (i = 0; i < MAX_TIMER; i++) { + timerctl.timers0[i].flags = 0; /* 没有使用 */ + } + t = timer_alloc(); /* 取得一个 */ + t->timeout = 0xffffffff; + t->flags = TIMER_FLAGS_USING; + t->next = 0; /* 末尾 */ + timerctl.t0 = t; /* 因为现在只有哨兵,所以他就在最前面*/ + timerctl.next = 0xffffffff; /* 因为只有哨兵,所以下一个超时时刻就是哨兵的时刻 */ + return; +} + +struct TIMER *timer_alloc(void) +{ + int i; + for (i = 0; i < MAX_TIMER; i++) { + if (timerctl.timers0[i].flags == 0) { + timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; + timerctl.timers0[i].flags2 = 0; + return &timerctl.timers0[i]; + } + } + return 0; /* 没找到 */ +} + +void timer_free(struct TIMER *timer) +{ + timer->flags = 0; /* 未使用 */ + return; +} + +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data) +{ + timer->fifo = fifo; + timer->data = data; + return; +} + +void timer_settime(struct TIMER *timer, unsigned int timeout) +{ + int e; + struct TIMER *t, *s; + timer->timeout = timeout + timerctl.count; + timer->flags = TIMER_FLAGS_USING; + e = io_load_eflags(); + io_cli(); + t = timerctl.t0; + if (timer->timeout <= t->timeout) { + /* 插入最前面的情况 */ + timerctl.t0 = timer; + timer->next = t; /* 下面是设定t */ + timerctl.next = timer->timeout; + io_store_eflags(e); + return; + } + for (;;) { + s = t; + t = t->next; + if (timer->timeout <= t->timeout) { + /* 插入s和t之间的情况 */ + s->next = timer; /* s下一个是timer */ + timer->next = t; /* timer的下一个是t */ + io_store_eflags(e); + return; + } + } +} + +void inthandler20(int *esp) +{ + struct TIMER *timer; + char ts = 0; + io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00接收信号结束的信息通知给PIC */ + timerctl.count++; + if (timerctl.next > timerctl.count) { + return; + } + timer = timerctl.t0; /* 首先把最前面的地址赋给timer */ + for (;;) { + /* 因为timers的定时器都处于运行状态,所以不确认flags */ + if (timer->timeout > timerctl.count) { + break; + } + /* 超时 */ + timer->flags = TIMER_FLAGS_ALLOC; + if (timer != task_timer) { + fifo32_put(timer->fifo, timer->data); + } else { + ts = 1; /* mt_timer超时*/ + } + timer = timer->next; /* 将下一个定时器的地址赋给timer*/ + } + timerctl.t0 = timer; + timerctl.next = timer->timeout; + if (ts != 0) { + task_switch(); + } + return; +} + +int timer_cancel(struct TIMER *timer) +{ + int e; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + if (timer->flags == TIMER_FLAGS_USING) { /*是否需要取消?*/ + if (timer == timerctl.t0) { + /*第一个定时器的取消处理*/ + t = timer->next; + timerctl.t0 = t; + timerctl.next = t->timeout; + } else { + /*非第一个定时器的取消处理*/ + /*找到timer前一个定时器*/ + t = timerctl.t0; + for (;;) { + if (t->next == timer) { + break; + } + t = t->next; + } + t->next = timer->next; + /*将之前“timer的下一个”指向“timer的下一个”*/ + } + timer->flags = TIMER_FLAGS_ALLOC; + io_store_eflags(e); + return 1; /*取消处理成功*/ + } + io_store_eflags(e); + return 0; /*不需要取消处理*/ +} + +void timer_cancelall(struct FIFO32 *fifo) +{ + int e, i; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + for (i = 0; i < MAX_TIMER; i++) { + t = &timerctl.timers0[i]; + if (t->flags != 0 && t->flags2 != 0 && t->fifo == fifo) { + timer_cancel(t); + timer_free(t); + } + } + io_store_eflags(e); + return; +} diff --git a/29_day/haribote/window.c b/29_day/haribote/window.c new file mode 100644 index 0000000..4d70578 --- /dev/null +++ b/29_day/haribote/window.c @@ -0,0 +1,118 @@ +/* 窗口相关函数 */ + +#include "bootpack.h" + +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act) +{ + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, xsize - 1, 0 ); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, xsize - 2, 1 ); + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, 0, ysize - 1); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, 1, ysize - 2); + boxfill8(buf, xsize, COL8_848484, xsize - 2, 1, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, xsize - 1, 0, xsize - 1, ysize - 1); + boxfill8(buf, xsize, COL8_C6C6C6, 2, 2, xsize - 3, ysize - 3); + boxfill8(buf, xsize, COL8_848484, 1, ysize - 2, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, 0, ysize - 1, xsize - 1, ysize - 1); + make_wtitle8(buf, xsize, title, act); + return; +} + +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act) +{ + static char closebtn[14][16] = { + "OOOOOOOOOOOOOOO@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQQQ@@QQQQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "O$$$$$$$$$$$$$$@", + "@@@@@@@@@@@@@@@@" + }; + int x, y; + char c, tc, tbc; + if (act != 0) { + tc = COL8_FFFFFF; + tbc = COL8_000084; + } else { + tc = COL8_C6C6C6; + tbc = COL8_848484; + } + boxfill8(buf, xsize, tbc, 3, 3, xsize - 4, 20); + putfonts8_asc(buf, xsize, 24, 4, tc, title); + for (y = 0; y < 14; y++) { + for (x = 0; x < 16; x++) { + c = closebtn[y][x]; + if (c == '@') { + c = COL8_000000; + } else if (c == '$') { + c = COL8_848484; + } else if (c == 'Q') { + c = COL8_C6C6C6; + } else { + c = COL8_FFFFFF; + } + buf[(5 + y) * xsize + (xsize - 21 + x)] = c; + } + } + return; +} + +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l) +{ + boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15); + putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); + sheet_refresh(sht, x, y, x + l * 8, y + 16); + return; +} + +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c) +{ + int x1 = x0 + sx, y1 = y0 + sy; + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3); + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1); + boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0); + return; +} + +void change_wtitle8(struct SHEET *sht, char act) +{ + int x, y, xsize = sht->bxsize; + char c, tc_new, tbc_new, tc_old, tbc_old, *buf = sht->buf; + if (act != 0) { + tc_new = COL8_FFFFFF; + tbc_new = COL8_000084; + tc_old = COL8_C6C6C6; + tbc_old = COL8_848484; + } else { + tc_new = COL8_C6C6C6; + tbc_new = COL8_848484; + tc_old = COL8_FFFFFF; + tbc_old = COL8_000084; + } + for (y = 3; y <= 20; y++) { + for (x = 3; x <= xsize - 4; x++) { + c = buf[y * xsize + x]; + if (c == tc_old && x <= xsize - 22) { + c = tc_new; + } else if (c == tbc_old) { + c = tbc_new; + } + buf[y * xsize + x] = c; + } + } + sheet_refresh(sht, 3, 3, xsize, 21); + return; +} diff --git a/29_day/hello3/!cons_9x.bat b/29_day/hello3/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/hello3/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/hello3/!cons_nt.bat b/29_day/hello3/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/hello3/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/hello3/Makefile b/29_day/hello3/Makefile new file mode 100644 index 0000000..436f686 --- /dev/null +++ b/29_day/hello3/Makefile @@ -0,0 +1,5 @@ +APP = hello3 +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/hello3/hello3.c b/29_day/hello3/hello3.c new file mode 100644 index 0000000..f71cedf --- /dev/null +++ b/29_day/hello3/hello3.c @@ -0,0 +1,11 @@ +#include "apilib.h" + +void HariMain(void) +{ + api_putchar('h'); + api_putchar('e'); + api_putchar('l'); + api_putchar('l'); + api_putchar('o'); + api_end(); +} diff --git a/29_day/hello3/make.bat b/29_day/hello3/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/hello3/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/hello4/!cons_9x.bat b/29_day/hello4/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/hello4/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/hello4/!cons_nt.bat b/29_day/hello4/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/hello4/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/hello4/Makefile b/29_day/hello4/Makefile new file mode 100644 index 0000000..f4cb8d2 --- /dev/null +++ b/29_day/hello4/Makefile @@ -0,0 +1,5 @@ +APP = hello4 +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/hello4/hello4.c b/29_day/hello4/hello4.c new file mode 100644 index 0000000..ec04384 --- /dev/null +++ b/29_day/hello4/hello4.c @@ -0,0 +1,7 @@ +#include "apilib.h" + +void HariMain(void) +{ + api_putstr0("hello, world\n"); + api_end(); +} diff --git a/29_day/hello4/make.bat b/29_day/hello4/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/hello4/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/hello5/!cons_9x.bat b/29_day/hello5/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/hello5/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/hello5/!cons_nt.bat b/29_day/hello5/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/hello5/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/hello5/Makefile b/29_day/hello5/Makefile new file mode 100644 index 0000000..366ff9d --- /dev/null +++ b/29_day/hello5/Makefile @@ -0,0 +1,5 @@ +APP = hello5 +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/hello5/hello5.nas b/29_day/hello5/hello5.nas new file mode 100644 index 0000000..ee62330 --- /dev/null +++ b/29_day/hello5/hello5.nas @@ -0,0 +1,20 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "hello5.nas"] + + GLOBAL _HariMain + +[SECTION .text] + +_HariMain: + MOV EDX,2 + MOV EBX,msg + INT 0x40 + MOV EDX,4 + INT 0x40 + +[SECTION .data] + +msg: + DB "hello, world", 0x0a, 0 diff --git a/29_day/hello5/make.bat b/29_day/hello5/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/hello5/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/iroha/!cons_9x.bat b/29_day/iroha/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/iroha/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/iroha/!cons_nt.bat b/29_day/iroha/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/iroha/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/iroha/Makefile b/29_day/iroha/Makefile new file mode 100644 index 0000000..df134ad --- /dev/null +++ b/29_day/iroha/Makefile @@ -0,0 +1,5 @@ +APP = iroha +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/iroha/iroha.c b/29_day/iroha/iroha.c new file mode 100644 index 0000000..3ed1dd8 --- /dev/null +++ b/29_day/iroha/iroha.c @@ -0,0 +1,9 @@ +#include "apilib.h" + +void HariMain(void) +{ + static char s[9] = { 0xb2, 0xdb, 0xca, 0xc6, 0xce, 0xcd, 0xc4, 0x0a, 0x00 }; + /*半角片假名イロハニホヘト的字符编码+换行+0 */ + api_putstr0(s); + api_end(); +} diff --git a/29_day/iroha/make.bat b/29_day/iroha/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/iroha/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/lines/!cons_9x.bat b/29_day/lines/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/lines/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/lines/!cons_nt.bat b/29_day/lines/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/lines/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/lines/Makefile b/29_day/lines/Makefile new file mode 100644 index 0000000..45a6aad --- /dev/null +++ b/29_day/lines/Makefile @@ -0,0 +1,5 @@ +APP = lines +STACK = 1k +MALLOC = 48k + +include ../app_make.txt diff --git a/29_day/lines/lines.c b/29_day/lines/lines.c new file mode 100644 index 0000000..5217faa --- /dev/null +++ b/29_day/lines/lines.c @@ -0,0 +1,22 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win, i; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "lines"); + for (i = 0; i < 8; i++) { + api_linewin(win + 1, 8, 26, 77, i * 9 + 26, i); + api_linewin(win + 1, 88, 26, i * 9 + 88, 89, i); + } + api_refreshwin(win, 6, 26, 154, 90); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_closewin(win); + api_end(); +} diff --git a/29_day/lines/make.bat b/29_day/lines/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/lines/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/make.bat b/29_day/make.bat new file mode 100644 index 0000000..e489766 --- /dev/null +++ b/29_day/make.bat @@ -0,0 +1 @@ +..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/nihongo/jpn16v00.bin b/29_day/nihongo/jpn16v00.bin new file mode 100644 index 0000000000000000000000000000000000000000..135f07ce88e6ddefe60f5b6768ac36b52ac3fe76 GIT binary patch literal 311296 zcmeFa4{#jUedpOT7y<(bA!Y`k2zeo*XE>BV+6h5Li6Jiy3`U>`P>KjrROI9w3sU5D zF3HA}>`f?%1e!3SjC495#3(7Aw-ukZg_V#jFYs^!2mF$*R>(fC5Nyo|jP$%hf87T2_0f ze4?=+N}ktjdfwt<0``HYOY7@P9|&+ad(yCG`qJwH(`Y(FZ*Tf~X(@f3>4FDc@OC=8 z*M0pVV3)nOYjnH-R!Q(m8eW(vbioI&?WJGvn{nG|xWDLo%@jOK%H?v5qe~h>-w(Mh zlg;HPy&*wnJTFkw`Ce~R!?cpgKq_)Dv+Qkm1 z_l?pL$@fS5l)p8a%Q=KbTe`O7k4IF5|=UNa0(50H%z_rq*sdnuVr**B)#C1gz{^)#6foK#9yk~n|lk;Db3&pea99v!{$bqviH z(pg7G^9e?avt9S3I{)jxo&^5v&z7pm>km5@k!#`|7)hiRakGvB@Zg8zlAml^VLLP@ z^M%2l4*hxtKeR8#x1Aa`$2+BU*3D+ubjR?g2R4Qg{`5c`djtGUHL9|_Btz_F-BHWY`(|1) znHh&iT-#QB=1yk1t`l&TwBn|}T)q(OzD&MN{vA+540kfP?pk9<{qYcLY$%x+BDJ2x zK=p=ASQRrAo?#5_f}z<8Qt(Xg=+bB|)Zv^1RciX97@wulNc;EXMwbi_aBnoB-utGc z-ax=`7;ACS8WRGBg8}=dVz_|H62U!hXVE7WcXHFx)Z8j*F4SPr-NC`=tl89AN{{R* ziz&)`Ja4;qpj4@^LLMVf4@?b-QfZ(M4lnKOVFYW<)AMw- zwKzY&*s7@nNxkgv@9oLCOTV?K&O0{<+nCF(%J~TcvvqGAo60m4)Y;J9BleVZs@WH~~>O85sH!A-|wM44EVdX=@#%A0ETl&(( z9Q37iXh10Tz#4(H5)Dv$s~LFSiWoaeEAV%y>+B0JM5uKV@Kl06jzW+pUoiPJ!-o{W zc%c&mfqEbhXehT4sI{@N2^PAZQBE_Gx}pKqWHbu`U4uBpl@iqz@U2aV+cGt)>v9nb zbLbEqE|zt@)J z9mB*P@rB6Sym&FJoUa4~Ar$%JbnzmF0=S6V`4VzMG5U&n%^gcJF5#(t^&z>*>(i%w zKY1OV_jNgltyYw&FBThjC!E_vVEc|$bbJ>P>3D};8ZQ4k4W}65S@5IcgJS$B$?|7( zh*Pi>Kqv-KcS8Q0t&|zddFvZ-0>0q;# z%1OhF!>og<)ftQrf+?>Y`RweX}???=*#Icza`-d zI13R``)HY5e#Qm_<=0>oSd9*K>v=1fbWrHFK^2!LFFcae<}kArZb2^#2#)+n$TZH57T4`{p4~= zr^8EOiiaq?-qHX?K&M?+;>$vQ3x9em_Jwo#alht|o845VG#u6{3?&q#P~A)_$Z?hF z9J~z;wmS&YGgvH_XCI!OEtiWjfX@EBZ#_2qWA^FcT8)OT1D~kYXJ_lxi3mPYt*@@u zt0QKABw!Kw%H?crZB2wslBd|;o84jLO~5bKmew1>&x$)~7I(}wRM;g<>|CWN>)=v8 zU#v)j*23iIAE|bId*0a6^OI5e$>*2Grg{$zM&$<&^-d)zrY6=Gq97-@-aM zb8USr%)pzeWL=;dF`(lDDyUI0$w@+|1qU}!4DT6R>fGS0HD*HGxkt^B44Vgw_!bK5 zOQDFuTmEEWG(VW@%{mLYeGPxA+32Hsg;w<86hAi!?c{I{u=T85FGGhc^j(X(7u3)r zYhDBhvr*asqHLVk*3bbCa+V-O}_Yn&i-0i(5>8 z+$0D8T4syskDDZMZjdOKuF)udI~AJE=h~6C41F?iFI^il{RdeBh7cNTKmp1!e_2>K zcIOUe36=UR^8?_d=T9mF8i z#JueYj9?+kp>WaOcT%N_q^?edi?m)D&9;Q!oy@c6?IA3u0|=>Ig{{o&R3-@p39cN>zg z!I3-C6kb}l0WgC={YpdV$W&_j>x+|}J42dSClhn*(;c|Fn5+TbPjNU?beoz-HJ}1b zHMnc%UTGQ1{8Q7-s3*}&BRj-NJ|7;r4k^bXgUvC#Os@)(^7&q2$?}7%H|OFXuB26x zSC9z*&^cUr=iYVKZ{zQ^tPY(g;bO!jT$vajhKf`$_fhrhHWtIRZ@6jxr3AoX5>Dcj zvn$2CuagwaF^Q|ljwXRtUw_z3@`qx}7@)Uwok($zEUZ_3866!N86n(KEIRxK2e~Gk zG&i@lrt+g>Km}8Z>ub!T|3=l*59oi2zGi!J?x^}U1l8;?OgAe3ugTL*|8V@{{%LmW zW|m3%cjPM}pVs15lEBYsnxJ!itrAtPa01Vnm?UHqL+|2}zLqX3mlEaSvyOgm`UN<&Q$8LY;`!=# zO9zq_=3w>b`{Edj)sLa61xfsK;txyIZz;M?eydj1t(3g4a~R2!A6<)55XpD{&i-)x zl+V;Jjc_X7h?8I+ly;A%@tJyK%~F)t`M0_2;@?ew*T2X^@I34*Y4E1dlsh9Hdl1)- z-&>QyXYwu6I3SS?-INHQR&)}6E6DA6o$(8nj1ij=IQ+IR$lBtgv=rSpCQH~bwI1@H zWsweuH2`;z;97EY=-iGSJF>9@)@U>q7Z-g$uHQ63G$(M#)48P_$<&H3T-R6J7k7~h(zg5J+5u)__`0QS_Z8NX z$uR%u*^!STe8OO3qWZ=f8xL6c!0%*Hsa(EI`a#I~o7H-K6~}ZktiW>wABY*uLp$az zdxVkimqtuKQN%{0H!7<=BGEPvN55vMz(gg0*r+hCz%Bl%Tzc4uC=i*Tko-hlk*ERk zqpHMHM*W^%r#}T!L4dWxE;B@8ZKqF$GinI*B?Cx6E+^XcjbTvds@9_hj0OhWRsRJ% zYucCWLbi~9qgttm{x#v(1<&p%rQnD*=NBJ&zX;&!?hww^Fi=6u0 zWL)eH2ZeFE;MxD9l!9ky6B}#={gX9F6xD7m5HX?Pa$rQm8d zlkH;xQf`L%2Z1-;3^=t4u7OvNttH`(KWU^;WEok70?#|^<^Dr9c-wXYE#epsePz;qY|BslN+8 z4h||1R(?374IMpgbzTE+go?)Cbe`rgaEwW$-=>-&G7L~RJi8<7rQv;3l=Xdh#8Aku zWqYZsurXG$LH5f?2&r7&@64TxoCh?qt!DDfPDdvu=8oK5m;OK~Tc4UEK%G5o3(}0t znf`&nJVA?jXI`h?P;awOtv&Osb+G3rie=*4^-%q2hGZF-pe#{;B))!mf3aZfwoRQZ z0SykAo8AQ<_=$lV!gu!fr{O!l=v-PKooKS09~_Xc66xPG9P)L+rx|I{&z0|Gncigx z%ZsKAZw8w>KWF?GH0hN`XuUieIF~66Z@ew;zCQfKHJ$NQrUcvj| z(e@7OpjX!3#Yw*+PVoYIKUXKs&2LbBA`yZJZA}mW!cAOHK(!301q$xFDP-%VHNeCi z)RSRtjZpQ}uM=&8OxlkDmIho>ZkM2M(}o81O_0ZNF#-G_EWS1`{Yl;~`99qUE9mc~ zO00WWo(tOVl#dl8LXh2KK3LWUj*Q-!H4O+e(rfGYPB%3TW@*c7 z|1Bri4oqYza-+9$Y(}UBfo|fyxP%o|$F_3$^@~l!AiN!ZW#a8;+|bZiit@xG$WWkG znvlj)1ZVcGQ}~xeNyWzsg{46JlTq+N_ape0SQnSX;0_RaiBUh`ENfo+$tgIh$*j1% zFr7`gn9PJ&z!Lz@;nubgMaGrhT zG-2b*{P$42y5ZIVlO4ytWFJ>irSK#SZfX}v^0tFhJ`HCm=mfB~IH$*@nJl!AkP8ZOi|fg@!d`+C!tLsk&` z36Ow`d?~nkjO(w4+$>fFQuw9dl<$UXd`y8g9*G2l~|qbHMC|h*(n%*=)HS#c>=s?m$yH({Rxz4evDX=p&+T zOE^OO((vq#_tS9r7xQ384r-7T2I+NbkR)9Ek$@|YQ706mfMgDU04@mwB}YWFYIYs! z7lFkZ3I397iNAm#-d3J9Oe=&0Z%9La{du(%-f~|(wu3;%KPBIym))vGxy`-AhKJW_ zI11#3@WE2)KDoD1d9@d=zl8H+w{W7$H5T1)=qJC%(g(mttJP8YH8DIUTgd+y7>BT9 zpAK0K4u9Mbj(5!tk(B&+JipR0sn%{_6o}~41*ZcyghL?hz6`x!>SNrE{>J_c8oMvo z8-&TD@k_#yzZ=56XP$kwtGuyQtXyP(HQZ3AR#Rt8rtGlO>7S^4}r>Rs|t`G_P3( zrJTP&dyWQpfSel(_c@p|Aly0cr2{WtWlkY1_p*uPQ@3IC}V@iSqLhydRw z{UgO6QvMORh(MM&5j-`38v2C&SBA9xPuoA0H*SgOE5S?JFX_*;eKN|~_9h=JBvwB2 zqfKdWu9NGhV)d5AzTNy(tnT0)CO47eew)%b_GwMK; zRNfKH9l1`@U*Z#vFJ~@kgD09>JZ|IXS`G}TbBCYHt7H7=074RQ&E`aooy6uvL0q!i z^Z;RWqay+m7|{|jVfFyHnz#0a0M}9s41svm>5a*G^)8GJQ2v=`Sv_m4^N5R;59!0` z^Oy?d-S}(tYqhgnyPi=e4=-g<4>qo{IhX&0Fp%JSK!j&dW zBx%n;{0(Mc8S*LN4=T{ZB@W)S3c}~$DB*T*;-rTrI^5l9H3WjI?HTRS>oN5_byoY& z^z@5uf}!rqB1aHl=$RwDeZCm%F=vGr3n zg?~Vy&lM39dQGOve5jI6sgw3CyLYh`SiYtoSwL@aSZ#+!7GTTJlZA7AbLzqBHxL>Y zVAHD6!Ikc`Z-Cgm$OiA&+0Xih-RCelA8@qryN!u31c6a*GXA6{A0BAt+LA~{+8sGH z>V2*D=41r7XkWg6PjqeQh20eOa#^CUa?gecc?BC})2BlKZDK+OV(TU*aN!SE<4{TH z8GgEv-=KAz%q0iqXy~&58yZj}QYXBs2wk%N{APFkMXMlc-)+x<2cr6ETLg&5cM|M6 zqvw=Zv7bkEY=bN-6zh#fXOOcj{-=JFTzwPm-mM5 z1q4`ITLU8zQOVd#@*C~~b?hTyM!gPKCr+>!zc^7H2HYBbxAfd^D?L|wceG{j{U-sR z_-G9O^L_h{{PvFjkc6LDJh?v!|I>Z@{yc_HES@;=K%)L*e|qG|UmQ6W!}p&!`9P}t zjvcA;`%j*H;AE=)H2kANKT-dG0KX$C{7;@pm*3Z2KNRTnpZ@*Dkt3b{ANYCgbv_XH z?^l0M=~oSZSjYB;!0{xEMRU@gH!!y(i-(x$WB;+~SE)JR8(T`!aU|@^4FBbY2N%j# zzqhr;|JsGuF04(wDFZ$}^YqhS7}_&-`0(`1IAgiB{rUI)a`W)mo;}msvX6ctj|%)P zlqXEXkgl%fQNaHv$}_*V8jyhp?`HIj*jvcDa*2<%O-qz-mgO5G7%Y#tT$dNMYgwlp7h!}q~1S0G};Sn3s+5e*QkgO2SZ!E&X6nZTP!rZC) zapC_uU4LY~@?kzJMF%#+4nRK#2{l~HFzhHe=D^;@gyfxWPd z19OZuBmnre8NwqkdnlUVgi{2YfI7pg#}j;I4`g|+@4q{WZ{RRF{g?Fr{-5~wap;Ts zn5engwd;R@nV!QuoFu4zYriQ(?VM**4CoG6*2zQ;Z!owxiChEW zsBv-2!}9O2Tyg-6$s8(0w$G!7$i=pxDLo!%iOXD%nYy8On0!V!FMV4y#_zncA6^UP5qYp(WF^@G|5 zpHBUny@l}s)oJD}F+aOzd{meewQu{cd*$M}J2w6y`E{owp%Gl)oeT=EDmf_aML!?-&5e{lsvYH2f1$4NL1%i_z>&Ru}`42;XXYm!z+9lbjn%o7Arq^OvX- zD`(*9`$nSwx+aZBXs@}X`GF;2M?ySZa?Rxl1iS0*{&RPOJR4zlDS4^*7(dQ=!ezb@ z!9h<$6w4R)o8aG!;Jjo4+IHs0jL$|=J`2Ut9z8`9t8%-oI&bzd9d6Nj#R(Pf;YyL@yVWrzwy-{Jl4_9L(xcrwK| z+)122syF%$^TqJ!`g-v2KAx6KUF}5eUsGR{?>gnL$=`LO9bHH5M&FLVI>)e`2prL& z9l23a|Dq0r*Kq|Aeo=cd;5rqD@DIc9!`hGGar@y(+c!4JZOBWO%0)E^6S-st7;$R5B z<5+(`JF@Ff-2i^5U#~s;;PL|>*}s3`Tt5#SelYwg-ez*BzyG@B?>II)`#A4BxL*BF z;p-4AFO{xS{~gB`77pE@yx@0rmA_|pVgGG${}+@}?I+=-JD}bT%U?^sWO>oIn|?|7 z2hlGHhklPkf$QRT2lVZxU#k2E&@T!9Ao_K~lk_X^J#u8>_$<4q9Dk|&!k=~M*9|xN zz0euIZn*K^E9IE~J_vs3*-rhH+m0PO`Eb2b3ES_cUw3(2FFH^d+Q zyFq!QZ=(FciTV3yug8CX%iC-JUtfLvdcGC+em+~gJ+EX-xYA#m3y^$U;%({Ode$qw zV$bxO;Kbj<@_M)gecEn^@bLA2-Q_LliT-j^H{4%*H+#p8D~00F z-iPb;x}GS;CAMol*{msYRKB1m6S)_`%~{qV%zuWdLylJ#`>uXmN_-TYId=c6j7?l> z^p*L6>NKY{lboNEgX!r8E!gwPwzW_Bq9orl2ov{4Z%I90-+aF7`FgTsyyWw@&48EQ zyx}G|z`CBl4;u6846~E)`FnGalh5Ze@xnD01=Jt<7e)x(`w_sdvx45FaW7oorBXKq z1O2ePbFW1qjZZXxRsUS=)_>ki*^`8~yrrcioXKetzElfRaB5G%sXYZ}%{&EX-kyU0 zO$E$RXGL#cNxVN|Lo;NVzwY!}*NxX;p7gC|6BMH)kYBh-A-;U>CKun&<=?W=@!yIf zwW$hR(Wnl|UztZQNR>$cU#^%lQo14pVNIC7C$6HYiDT!%_V~WBNqkkAYv|o$@wI!k zOXsq4CjX{Vuisto=>IFcE8@GeW#=D68+2!X%; zW4N90e$5n>gJv^G=LoO5a@hnkoiQAl_@+fp67&mdzAp|>Cs%K$b`cK}DwDf89`!OD zzAfz_V3ocDr=yzaMsP%oR$4ayMF!&XP1pTIdDnp6kK*FXP2&xVk+fX((qC>3QlJ_n zc5k=J<-iXFlW+)^hHC(l(mP{DHaxbK6m zd$WXld_(b_^!kQ5*xV(t9imlh!Wb5ucL&|K?G;{Ar;6`;nG~G<8-q3l0#5f+aIXta z%rOP0f2s1cA59JTR;7UsaiZ@jco0L}2~o2Y9O|WV(0&Ro^^!`4U4B~Z@j>sm>B%KG zsCgdCW0s=*X`r044?$4tvJaUQ9Qvi<^v}J4$LUYxCj}RKCE@T-3XXD5!J%&o9<861 zDMY)J4Fg1r_x*||%XFgyWMNGWil;Xzjo+_ zY3hwt)>$t9Npu~@uhl~m`^QLyRuC`(P$0Fw-~}QQQt0Rpc~Wo@API+ZDYzso3HRt= zs(ywz2~V3I;T13lF6m0`CzIMw!J%Fm9hx&XQh{E0LGZx>E*wgB_6?QA{>W|Aa_(}VSOOUpYxK14dKzmI! znn+#xiSimMONIdDWg?srqg<1v5BKHlW0(G=d|Ll9IBEGOM=Pa&=s_yA;IJ^+ec&nj z0#DHw3{&z4JSl&kgVTqQe;u4ELjDr@-0MAkk7VR?`)7KkdLyn8Of83{+@(W};bRA4 zyuK4eF#L~=%BSFfQgHI6;LWDj4cG8E z38(*-nr?N9Hwlh~cRt_?0l`#6Ns{9dm|tu<^aH~$0@$}u4}p9+ko1$r-i?2gyTOup zL?hWXy!K`#S1LMc{FCLag}A)S6~n_GM)e#0B>{1wG#e!NC{c@&BQYajloWm&YQzN1 zi9F|F`nq3>PQ!2Er-D&=744K4AYH!~q~QtwR(uy2?-W|T_U}3RCiM$6OY4_VHjTmQ z{bUk9<8L8m>cmLBr09n@)WgqdS^X(E*r(vmdv@x_{8K3((6r-bVT?*s{2Q)fdTZ+agw2NKjN>EOThi|@^xf957!GZi;-b!}R6@-7NOU2G+rJaF z@7!!_U$Pm~7x%{+)It1-`x9S_KGYvy3r_vaoHAwBIowa9R)*OMNqhBypl?5LifOhM!H&lW_5860V#n{mpfxzx^pE zp-DK!V|XP0vj2{Ler+Ai9=-ofb<=(4{u6{EyDz087{UhNo z7E%%%3JL$PeH)<=F8$)lC+Tnf7a&Y>fK7Tr`oRI7tKIo0{Q61?zC`;;xT=9MT+#`n z-r_@Asx>A3sT2gMOQaLztv)yZsrhuyvV_k^MeuljW`lPa2Dfbhjz1lHBiDhO|AZT0 zQcYR?JQwPa=P3HX87ccm1u6RmaYR~6;(y9Sm!>~x0s1HT3k=fy6^&1>C+eYR{K4x1 zg@Ja(bjG)KQJqhYuj-GIFi`!qCQenIqc@L)-GsCE)vNRF?%&^><1_^paW@!OG6 zT@eJf3aBVdr&U2zzwS91jqI!1*4?HK$&~9^T6e4w9z!6CF{8rK4wP2N<6#ea*}D|g z9Thh{LlMJFb5rPOvZ5+Cd3MIBIbB7`-Zx_xj(p8p2r;@vxxAQtY3j7Qo0KngJ(6#| zXi3TKZ;N)D*%+XaeZLygFOt8Af=lbJ9Nn~p2MBG+6;il4>G7Nr`m5>SN&Bihk$sKY zce$?ZU-$%-1G{5HKl|?NfD#Z_JfyPA)QV*_!awSdXse`BnV2h3Lr}8Wr2kU{Jojw{U>L9fn++krygGWCS$Q|oi0)Nw9 z5&o{66d~(I zkNh>4RXF2lAIoUSUoB`52(H8c^MbBOda(TVf}~FW!5{iX++`Hr2*=;b3!W^`AYwtB z|DX&wC_E+8sbAx_(HS4XVcrhBW&2lC?Sta=;l>|e5OtFBsy(iNOVYLcZOC)jld%7~ zcLw|t{TtKnNT*}0#AzQ1^g86@CSF7=pOW8NO#@=NIjH~1{;B_o`jh-+MI!wem3RCf z%U>v89r|XoynZ&+Co1FnJTS%{@31_yOOa2FD}2JiHH~~m@)5~rBp;D{rr^kD1h*zE z6Y>|CS_u&$oL1O=Jim$H(!WW#%V+vm+#4pdFA4d~@k1ESHE{InP*D3Xdt>>BKdWb7 z9CrL=+@FX)GBmQ!iTEQq67XgKGD-Lc#m|!C)9pX1deB@(DQAX$+ZS zoBTFwzS!4m;jL@{Q%b^@YC#Il&kI|g=)eZ6==6iW1EmiFTzjvRRb3?M@oP)1CUx+f zLMyxu;o%iLD7Z^Wt)x30o(wZ2zQP|!j_=t1s_@-S(M@%~D>>xCo7cc2xr_?6q7(Ps zjXJzhOXle9C{?@7@N}FG?j)41!3#*PokR!5E;`kBQ1fH0r|Y&3iDX1i90W?{Nr3D$ zDjMav9z3e%25@WYdT^<4ESAsXW$f+8dk7P*gnNNOh)8t5!2;UEXvbp}IAI|ycTh{y z>ceQsK&QsKnVcbfK>bYw)f#dKdy7iq8a_>3g^|9*J;902r_$0=>QZ(uIlv5m%}?d% zTxb&0xw`gDVxGJ!Eoaw}S%`r_t@CVUeDgzbMUAHF_hSDxtb=(_qBcSu>k+SZL%Jv* zl}ZU4th5mU^qm57EeompaY|I*e5_=CipxQa z6U8?^lw@)4=;RC%5S{a_{bSR5{5snIwYjytY}d=nwm)oWeEO4IFQ5D5Vg3Fq`^Tog z^Umul><`Hj7 znR)&7xcn#YI;Zr>Plo+_`8PhV^cydS_;J9fB84wdj|}ccU~X<-dEmx z@4EGW|6Bj~AAi2@z3+ejI^}mRuZ+KUgYqx`#>&e04e;Oj{r5odM)-gJ^Iy3^dC})9 z@4OR_?_EE;ynOEI-}?AuNWX9W)BjQFpMFdDUz;RUCR?F+WwS&E!lc~3ua8T*7CT2; zUDxuOah)wiaC`VG!T3D8$qziJCYSI62(w04<^}jD{~)@ffOYiy5NgjJ9!u26tA+Um znOsi!D;3YXbg5z~D$fPG2%X?vxZrsg!X&tqfW3f-N1&tpddbQ~CdARTEDzc@7F=0z z40Y!^zaz`bIeg_e{2CyKg^SAj#ev*F(XZ*cRHA+TKy&HBN#tKYPgSqoJvX=4?GI)D z=apjd2gO6*wihG-uT<)F_K)q2_76jkLrJP_562je`}|FeYVzV|J&?8KlE=q z_=Wh#`=3Mn)`a^g{zt7bgovUXvv!r@`ZL}r&seTBQtiSlk z`PoXe|Nff#S5fXpg#NeVmRZY{q-@t40XHcS4`4h z<%M6#@Xuv0GkWE3;xIY<8Gnk;M*YuaFEKigyi%!DL-;lATeLG-9{Shf{f*Qw21)S8 z?A_3-!yoVuHDoVG?Tdc(&iG~7pU4Qt{O4DB-}h_+zmk42cD6G<6Z3ONjwI;++_Nv7 zI8m-tI`z-Ofz_CPmGbO)_CI#|5B8n$&(Z!XuO#c=3v{-gkPpgdGBJPNZu~J@j^yM0 zffrsme_jr0NI!q}o@D)%%U$E|ADx?{{b+ya>go^Zf4ROIm%p3hwSzJK+3%`?_dE3; z6@GF5DwQ8S@=Cc}c{D6vE+2*b^-5I%DyCoAtm-e8o=DbzH0J-@>Xq~7|EF)l-wqD3 z>viGhyZ7(pvR8#(j31|WJ9u3GkID>C2Y=D8R_oAD<%`9u5&o6R@p?T$fACM0uas+Z zg4^%Q8~zzRf3q5u_g(!l{j*oZ9OO{_<{n7as zUU;@6e?I189{l6+&t$%NSBPKx|4%ohfLo;Y(0{edzLYCKk^e}3E>}!{#r$vZT0NEz;N@?kKQ2e|;iC%@`k{V#c6Rm$ zv3}70au}#n9{#0xr+m30^V5NA|9i6jy*~IQ@V`+{OI&s&PrylGVy*|Q4p$%BrTm4kx!lOe+q-Uq0M^qS?}kzj6D-Vi>R&2G z^m7?AyGoVvtmpsa7poKgtwi4a<_wTr?wMVB0nt=1@$RYK+(30=KVDwc9WUx%Ci{_n zb;h=s_o;Z)3t-!6urS)V7C8Rm-*+4r-RQm^lZvl(exd%K{ChXSB)O(R(|sy=^&LW)u}3KH7ehMyF2=I_*$*AKfL?8v%jLZU)$`W{S}lB zr_KXKUZGm!`oaaq%hCnSPj6^E|33ia{lEtf9Qa6n1%=e#Ki~}x#^HOpTeRy<<;|HcnF%AfX@WAux^+z8)dGgq?WB1$>kN@QSn$o>LO*TBc`NhT4 zi;MH~3r9ZS`W(tJPQbrsn$sQM^DKVgYw&A+_RPOOw>J+|0XLq z%Gm5PKZX36BS-E#e&4B6bNg-^@v4_DX?F4B^5c*H;cb;F`%Q13y}N$Ty(jB;*YOZM z)&8UYe)}KzM9#AxPP*?w9BkBab;O%Hd2C_!+&5=uspNnHHhur#!3Q7G=fQu_-#_fl zPvi$KJjCnrXAYe>apEgx-ZZv(;y)GXzc%Od^Y_aP&Cj=q=|6GuWeJW z7yjX2eD$k8{_6kmk3Rd=uYUC(Ui@3>Fv)R+c;>+OG- z2%{f5Ns2X@-2PVGQE;qaFYsh1xIJDZj|2FJ)&Dnz({xWy|Jd~OSbvYL)#=C4-~5B= z=|6Zg`jPbUM~@skQM-F-JVbpvvki5Fz%JniR`M6IFNIvsa&RKUm^@r@S{vV^=8Ne1y!OWbuRpfozw*jgKrfZ7&Ex^- zIG-6lD|~o}djp@N#Ve)xwj`np^%c9aU&pX5>>(Ngg)p>1xTijPJ4*on_ZLfds((1V zyg(@k+T_vusfAiw@&Wt=aOD{BrW$JmJGYRwwY6M+O7P*3K8W;)2Q%omZI)O00mW=? z%**$Seh*lA4%D6F$1mC#EU`_?%ikpU3CijPlSbc0WBW3%`xr(aMwZ2A18p((ZF`a8mfGK4ICKK~3B#L3 z-!`N3+G{7|VfRpfe`&<QsJjhI`R`b7iakDW7t33?~##14u5b2KL$v8 zM;XgYHh#l*oE%mM1@~Yb{rl~&0rzPi-*WN+>W94auhD??#$RoI!3F*t8Yrne8HO2R zy2raijvf0m7~o%FK&<`|@FT-+@*uX=QXTQ(zis17{loAF+Qr(RYqaTLn=Y=u^x}ne z=r>f{{WA~k+O@kl4vE0$d*k1J^xG#-y`BHwVCfOs&+mplqTVjy=c)LG?c5s=pL+ZC zT+Zu<|B90j6vF}Za*b_%pJcoGH5Wc_b zWmfbv`EccTi~fww`=~&bmwfc^E;;&$hrHTWzCHIlXW6rG*4tj)rhjVx0qCbc__tlH zv@5^)+HcxtC*yxpVb{kW+_h_DS7A5&6SQ-ix%MA@af@EIFD&4m1_lC&Ov!C#f}Qcn9abauN()ac1Sc!%RHiML47K=+;bb zXyh?|p<6#;C;hom*c`lR)78&i)s1kBd*Qs!i8i#e-#_D>z_;5YtlA@t4u^NI7782o zUuZKO)YdE5s8B3d<~-;J+xN?1DVSKzh$Fgg05Sc;|HBO|*b@&k%7Zg0vlH4`q669N9hW)S@9*_^XX!j?YzbP>KTUi|G7!SgUJ$whk(mYV zy~ksm(A<~!RI>F|UYE!a>4%e6V7_wYe#Xbyo#;B3+eP}R>YRS$uJ5cXUb*xrb?_4p zJ6X9KIg@o5>91W~#vT5C5+h3M&@BdgYZ@zWHUZFkY;zRI3v+1K5djP1EsZ&HXM_ z>R*<9pj|-pX66J6W(fHD`bzQN7K<;OD3>pNi~5<5eGx-2bKt;74>SKJsqe)XUU=oZ z^)EyI+GqGQsroVgvV@L2EngXDy&cF_Z??o^y=-By6RqkhSEXs()SvTmjbzu*s6@g zt4JsEE2=y&(KY#O!^WX|CD+N4vTUJ5aH1z|Z@k?_2E%{AvVRKiz-P3;OS_>gG%VjX z<@eL_g zdt$HM2-ohy!HIjBA8zyOi(8n7t=jg<_j_^K&S)ZXoX;5{Kh>n#+KL@#XJ>#v#oY1O zy?mZh9830#L?=A+-&}bWpMNsb1HaNF{l`sM%kKFu`BeeNiiE=={Q~*JSF^bHGoH1% z)sZ7d&Os~SMl0naZHvB7-RH_X1WkcSny;b&G@xhhjqzs#AjL!fYkuv^SJnR0^YdU& zrYG^BiR;LGg*<#SVX16(MIBT+>wbpuJNh*ROD_izebm1*w*RMXzByXrcl3^Dbfel| z5DG@W+!_WD4JkK;MEl;80Lde;@H^X>pZt~oqFDL%pdR26{}Z^Sy(u}uyF6aKPQLJtFO}aZ)@%TB)=&Fy}dK@3-{hf1IM1q@C=FR@9i=~ zkRu0wcztIU?)^EVziJ1sMs<5%Rr$$Cyp@m0c_XIamj71w&#DqHE_x zw;!FwdS;$h`wREp{}gXf_44h!)$g_GzvPz=9#;pB9ebK5#pwUE-yUe^Hy8f>slR{W zQOSRiQC`W7N~?2*xSd^Zv~Pn{StY|6IU4>h!;+ zLHOIG|K6u|==uKI+1hq(s}6(S@%G_=H3|I5`$c{T3#Ymxs3e8D=X{?P%$ z@44rGKD%uPhIc$O1n;jHi%e7BCJ&Hqprp=%>RBfCU(}DIJouRtimznwA6FXF2fp#z z@`2pzBbcpBhSpSpM9*!>H~jvaq;$Bv9A?NAzd{jup+AN$5**ks~!L*B}X zaef7RCHM587i>2+gZ7cLa)RcjsBgwU=-=*Rn{Q{{ME>p7_gAm3Qq9%U9pVoqZd+Qx ze!R5irqBVY9o|pEbze4UZPnm%i(Lrr*2gnaXOUv$RQ5dyM*Pnh%KIVNxT zN9I7ORoSE;>45%7mgkPuZyMjk892Ua*uHbXm{q(hV<{&U{hKKN1kJm!K|7zHa=+MS z<wU|6J6Z?%3`d=6>J;mzK?!xG4>38&3HcPQKeoCQ;zXSefaqNdnd%j@$X^Yo) zg*u8EywT?@I1~!EJ|X>FoBQ&Q<{Lw`<+Zi>N%-IOf4ER8?ScNiUiSHa*2w?V*OZpM z=8W)n<5L*>g1T35mDjiD8&DxHc;RUsieslK4t`tJHoCX+N2eix{H@`_(?yx^TPWY> z4NkV0Jt<2SJEHjuuLi<>{WX2>e4O%BP<{2W>Yb-f9r;u-!&}?g$LT5JN3Kx z>#$$ptjsO+6MY6ZU^*sF{IwOI()gd{Q!L*4h~UzT`slAFIQ4@*$34H5%RBzsuFSnR zH~0BB@PItf8-9wZS7CVUw}5)+N3?HcySlxjom+#yD7nn1wC4%a?}c_@yVNdiGet+n zeqZ!e{iWeCh9{G`X8wqOG*TKz0#`~)z22e2!nZ zg5J!3pZIp^?HBWJj#OqfKH@Ltx1+zj!|eBV_PMPF`g^VNV{D~{?rAzv93K5;-r|Mr zY%_3ef+XJd$&=6@);|OO!=f+zxu<14d~Mq&7xPEp#WNJA{?EyM<2FAUpZT%h&c1%> zLNDzXhP8qP0T^QR=V5|do0a8LXHRXv_L}e?A9(`rZ)Eq_=MWh3w-;Z&vgfVO=z8@jXStcN4p4!(2pJ172)zv))GRx-V3#??(IwU_ek+T_sI+PiB% zTzj|r*VMn_O&6y10~#}$2m=qkvHp!q-?(&XSp)G+XO@{E2!3$-* z(8_n}r+jvG_0omsm^{At>YraIE4~1JbWHWDd|`2MdmSR5I(6#81>%_@{;qwif0aj* zp5J(xzasi430L`gb-PrO|4C5l_lf5?cn5!V|19%z*`d|dXB6K|;5Wp!SjT%(;)N2C4^@7=fW+)Zqn@-`;szI538i+x}H)dR16cHd`dzhC7s zUMuwP9@EcCj zhuGDF>f;~3_Q$J&JNoRqEgb*%KKtK%_7912HMaSa{u?jPV7jZjcd{NkCV!vqe!Fy` zRLZW_aky9&&yI7eq?gR2A2fSF!=j=&fk7hw_t?G8|7Gkng|JBk43r$dLd?IgugK3> zc;{GPTb#$&`gDy%|B1h-_yy)K*k3~L=J_+1d5mRzPZOw(LgDJ%{G?xKU@*o9cFdFy z4D*!!&6%FV-qc%In9^(CGx?mvK9kO3<8D38q43jQtv0{*jmtF~Liw-45A|dGS%SZj ztGO?EXXz(A1pWL%|2=-O_i;4PaAD#o^10nO{rp~qx6JK!oB?>R97s zb@Q2E+kSva@Z3svhS>)5*BKA{%YTjV<5{!cgQtgOAE!Qkk{BEOerA1(xd)X?$(P5C z{*WKy&v+x%yXijj+xdA-aT{|3o2LKK&!vxiVPw~6;p38T8JODhR~>%-@IdzN3O_$N zJhE@1cJvy!=pzPKVk4pG%gkG!wJrHi>YfdOIiaS1H<&$d6gG?k=yUpqa%r)tE9@4H%PSC9R7`AJ)^!9Ee6n*6(WF4`K0=#yJ( z%p+f7G@tPmhA7X1mcOCLHbY3~bt)F%lVnEA%?e zI>AoDTeM$@7k7eS*~^cVK31FFi-Py{NB`LE_@DoP-4%5b@IqyzzjWJ^{SyZk7VwAE zDNX5E!eBm5d^H8{r+&2G{QN)mm*1Ee{d?!3Z)GkF2^oDwtUY{;ec@ly3PjY@re|!a z$E#MPyDBWV-fR z7k^gp)ztvkkY}4dwU(ts&y!3JHHozO6GP7rv$T!D9FNVE$FoClhM7;vXLhULZwv<8 z7hn3FKy>DB_IUl_xubJOYvFbFYW@AnmCBW!-pI(x$XMPYYRtPu-|f{)KJMk*n^Pl? zo~L~%B+9_y3P1!wV3ZL8*1mjKmu?<~zG4`Ag|QTg>@({(yC+$|a(UoiX79{D#ND-8 zpzN&Q9Wv&J%i#~7LDMFwhN(y3y9FQKB_C4pd%u10VuiK3eEu=B|NX3Auz+J8hRScv zY3jU{N4sl2zfzl

clFlx32D{N;gmG?nFA2fy7V+J7`*AlVTPw_u6VZrul-QH)< zlpVrOW*`Eaqz-#L84Y2d!A!9X_YxBt3DCjH!D{s<_wpN(j=wHezWw5h`TXyRzh=;S zOaTv84jemH>h*Fcme+G@)fY!Nk^hQ={J<|f_}~e3kM#|@9U2E2h&I&^Wo>4fAIeDo z@zatJh?yz+Wvzr95gw$0nYjml()1%r6=OES+s+09gFD@n9Xga9JfsO0nybKbVKDjJ z8Ve1$k7o+QQy-r^aY8%Qpx?I4LOb`aW^iMAK6D(vmoW6wNU4JU^J^OgpGC-a=7ohi zAxu}lx1yg<8o~r_HZ~gyk>neTlY{U>*gj?yM{p{FJLSv|^bMXi1$ft;i;MKPNc~;$ zuax}fy=s*R%ltAi9eq|zKjaho18rVui|KRAtRXT!3@w8zEX2XmU;H@&G7E*%W*FG< z>{wnlNTm_GylkPsxc0?ezYSe$x5k_uuz=9A2F*ulqt0Ke=A&;Jab z?!mt%wLQPqDER!w6YG}{-R2*q;n7ESGJhB;!GCYD<>c-BOZ)y*`UlPr8Bp}2`-L;l zBeNdEWs zT^2q{EAA^kn&Ng>^cflSt9k=P5A75DfW5NWr9kt4{FCevzmVy*^{1oWXu$Hd_dHt! z@W4;Cy_#S>PvBdyylMUm6Bl`o>+-(a-XNaM*}~*q4~qYhKejcLU$~HyL8S-N&=uKKzVun-3^E0(t4fBw7;TVg*BX6O8 zJ9+ZC=PdpR-#Zy#2~p#Z{D-5rX}?Lkf|-AKmItse@)4CsJ)JZEeBYD& zNEq$4GZxU;zyFBbBS}X_Do&H@Y=#gnl3S=)9(P(|+Z)yB-n0&6JNdU?tv@ zUzzpfpUqVZ85|W<%iYjFS1*^xS~kT%)3L5RGF)Q*s7V&{3pPhJ=6~fS7689D@mKpl zXXA6YdOHkP{YgmXiT;aU>)k9c1)2MUD;AzSc4Be<=-k{d(MiFh_zztpKBw?5o7;}e z9mN5^8~9@5H*uaRUYq|X@F&svg~b!VkNg5O_XdCX>ZeRL{nCjebBDoar82@4*7#)_ zeSqq5Hn+Z9c*blKQi3LRR!;~ZoZ^7Rv0N+2T zFWoi%XMEtSkiR^wKS{+E#(g%BdI5tgyNn8|lrB6EKG|%&QsNh`N|iePlq4s**7~7e z%p)Rwr>O*sjfbLXjo;S6ZwZwZVK9N)q>m4FG;LF0O@o=A^iIL2q=SU_Y~OIqpZAMD zD|1SYc zHnOJTa^Pa!%Nq$fa_uc6+3XH>+E?2Z*&wlv`=C!7t8M~>@F>lwfF>R}J4k=PfAz|4 z?u@V%a888B``xxV*j3R>@ofumpY82068~GSwP&Ad65w7$NrFJUe(+?*;>!%2`_FCF zFrDX847uj%Jg!-|YO}`X$vpVu(Ztc@u z`eRn?#GkjV0Q%h2zm)&P^ktX{+_?eGKk%=&suOL$_AiL>;a@`DD$$w!`wvbWpV!Y5 zx4mgLvy7}Df4lbmFP_hu@7V-x*V>W4rFaecJS0!IV4a4Yvid00*k@QU;3KzR9yUs^%F>3D&AI8kYz>osqh_kXZ(gd)GDqDVS~z^?BV>% z=*JGs_cJ~PNr3(P_kGFpSr#vkd(+-Z{=okEU$_SD?6X`y#V1bN_^$`Js13y@`n+QK zXm;HHT=jN5bP>wyYxx^POpWSHk?Qy0)_Kc(K572lzQf)U^f+C(<=_9J#rKGxjg-pE z$YB21v5B3dk9bV1HTB#k_%^@rEbFb1Znl!`Wq%;zRfj&f_tTX-j=jqJ?knG9yv7%Q znwk0JLw>o|GlqYt;6h=Kx5ewVh_CW^h_|Alvl!Hh_{-ZyHhKwy%+DhytSn92|4in= z2k#btk>nfC&#kRy$X_U)V1BX435wG2L)Nx|H=bqxUf93GUMBQkO+D9E&i|L+J^$=e zZ2YnHg?#>}CMNEhxNVm8wS2qr+;h)2{^)=E-3rRY$@^TL75?M(xle`HmHL%R<;v=X z-&FjX@XlR7^D`$FiKOpld}?MsS)$#_ZMyZbiGvepzlnqM$4x&y_bfb;Z@l>8rAyF< zK~W07D6hB_1eV5-eqNb9j^a5!fBfzvzc35`pt`f~XRns79=l^8i~pjv0R?zi;CWOF zq)ZMq1Ms)!-+ftTv-N|~$A?D>#JBde>Qz}!e!z2m>EDUJ@|jE>2g;sFokhO% zTv5iu29e|+59Mb4;q1Uo1kv$dsXwFWnnh3Xr?smoH~L71*sUoD#5kx;?&JjnfyM9g z`GEr;o0y+R+m$M2UzS&M`PbQ8WFO+QgM@z~_$*zXm|)?7$*Y^cO8)u^UnrG+deIxf zzQ{jo^?z%A;m?M=xk}l~&FwD?Pb~D`vVXpRC-EiJn~!M&^^-3)-X%WF{4YPO_|V6W z9kclx=C!@}Uwv%;4-PCeCcS}~1N`BoFb6IUARk}3aOsWL_y5)Y*Dqcym){BX|4^}b z=zg2u%YQGJklb(f5%gxt2g@@P2lxKuq4JCedg$-m*2oV>-W`K}ZvOTK%^z--{ZZ&m z^Y8cn_32L?tr7nkDf!6%isXNY_yJ0*UOyj-VSU*v%sg`QEi2AJE9}R=I6L=qvn;>M zMax!xpSLaS9vOa0)@|%Dyg>NP^j6Ra`I2{y%?V9{`^jh&uHO*{{kB%X7S&QA7RO(IBVwrPotViS4_Ta z8YaWWrmrYILU=@}U9;ygJp9iQmXAi10sR^cE$p89_#F?NEDhWKS^Pq|IMlHX|1(mx`pF09?>o6vTlO*@#a7N=P^{0b zFF~MM{ee?4T=Y8fCA17NfWohT3H41CW@<<={ z!?u5V%azj3J1#3eKfK(B^Yyd;$<3_tv46R?{gErLJ+b}TZS}SSF~$7K?8A7Al~kfx0Rl!7ZzeukO)LA*xN z?YTs7FDXB zviUJ;wKzUWY#$ciwQCglf%V`K{%V!}O~q%_yJBhFKUfn1CHly~)ElCq#&37=;ZHqe zs{LbSd#R4je`(`=w)2OXLP=_|}{-E(A1;a#*m z)7?3F^DLm8HTL zhqR%oKJgFOSAV&oGkwrI49+rin}yaM#(#Ku*T~4e>POGycO$>xm)-Ioz3|2Lskeva zkfZ;G*kEk`Q*M4wWcSV5(p&h~fx!=&_^uQ_Pkcq1{ry1k-*)alf?w~HoX=5njx|2H zwYjQ&`VPOr*r6Yv((LtV?a*Tbp6B6Qf5)4?%y_+>ANl1_{^&ezkgb0(cKT0F_3*PW*x5DUfQbLU&5cmA)8 zkK{M2*|`MRp8>wo$k`q)?J!mRb%lP!B0_%jU#-Rt8wtpagTrH*fylaB=mH|VVH61G z|MDM<3P)Xe&tv-osS?H?Z_4ApoUr)3)o;=HFg{QFGb%nK<%#~MeO5l0-oU8z53sn? z23X-g!18}>fVDm(`msUo9FJez`h^ViR(#SM|EvCi@8E%dK z@h5N3x83I2lP6#H+MYKHG=u-BWbvtZeA(RyoPPU16|I8!;754skG-?Gv)*!b^e>@D z;hZADEV7P_J(|&V8`95BOlW~h`w#F9XP~V;0W|Eb699)srPA9Y`TkvxLa^b&sfSd< zL#Nnn=q>V4%zAtM!iBeAY&`pWmxym1b}Z0$7CyL@`D(brh&J4RWL2I4>@i-D4KevK z+tOZK2a!U70b$g{TF(4(!Khtj@gL>J1^|??rgEAyoFxvqoP+-?v9}gSANjDxnM1E2 zDH>nXf3)FR(0q6JtnkMOTK~K8XSaR%XcQn;1f!2Pw!j?t!Zq}v{$lxIry&)eG}n6@+rAlWSJz6rv8+{O$ zxxZimA;b1%_U~(x^RcJto$KEm{R0vDhh99F@4w~NkM3XK7t!->eTvZQ5809aAnQlv z;!W8(R0NN~mG+v3PtynOpzg5u7JbZfJdm$eXR)JJyLeIWBXa(y9=<|P=>;62{qqZB z8W6@0f3fvGz-?Xko$mz*i2%h&07yxcEE5+XD1nq?QL+-# z4n=?vWP`M0lQd~Ne@)9u;W z+OngxPA1dV9&g{9H*XR}tF~_1-6-00M^tPt>4-Ili`+@_V%1V1bisMgb1I&e!+q>h)qmREEF)a0BiETr%#O-6oUX&lX_5v_>2_ZNV$)4YW zH0sUpHR#0BL9H*4Q_3YXC9@9(_Jw8pVjP*57X~nRm>eKjFM28kGft<|T?TLQ(>b>TjWPAOT!jPOj}0bU|7Vq1tdWs|@k~!lOu|3f z+dB~#1G`ScykqohIsRJ`fY1-b5N<$=_`Ko^cHQ}LC=~Z%{~<4ofrfk7H~O+Hfb0+3 z^?U+ Uf>;Y0Qnog1f# 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 literal 0 HcmV?d00001 diff --git a/29_day/nihongo/jpn16v00.fnt b/29_day/nihongo/jpn16v00.fnt new file mode 100644 index 0000000000000000000000000000000000000000..cd7387ab0020c48601dfdd25c1d59d769fea5b44 GIT binary patch literal 58084 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 literal 0 HcmV?d00001 diff --git a/29_day/nihongo/nihongo.fnt b/29_day/nihongo/nihongo.fnt new file mode 100644 index 0000000000000000000000000000000000000000..e312bf5b7e4044adcff849980606951ba48bdd9a GIT binary patch literal 145472 zcmeFae{f{ib>I2A(E~I6mCA03 z&@8={Qz;Q*X?Gz8Lht8$?t8D_>-oW?T=^%J3-s%E@45HfbI(2J+;e}t*PhoErfQS< zGoF{A}$^?X1Dm@$npi^a$SDe@lNK@yTZMY*YCMb`J>OnI?aH=LtiJ zcwfFZvzxfGD}RKqMo@i2`Q7<^0$%(}dx}NkQ^2SAj_^hC-Tk{$^h0fbujO~`>&s@d zqVG(zY4ixcqsPUwy=nOFOm7N4ly&q*<$DJPhO*#me)f|_f7ITXe;>Fd#Xr%f_D1yf zcfmXDbM!{}BmVZ$V9`&==dw%LoS5T6zThwUg)p8UJ2WTWSO6Z~=I0KLb&5nqJ+BZ2 z-Fn`{#6$f9LlLg~!%kc;U18Lc#yg>C@{M$$w^b zb#-mw#O3wpR_?vW^KyBRCIWPm+d`gpctOqg!?^F)0++L}{?ODz>z#sR*x{2vqubF@ zP(^7w(M{rebky^**&H>BKp(*g0&lcht-DaI0{8Nx6ETaXiH`z?NXx(I;@}v~WwUk5 zKR7rzGBQ%FHWqWaeZbFw_LGkzTp^tD#H|L)zgVw_6ch@QTj2+jyGHSP{f^ti@+8qR zU8Aq)#-o130>W&_TVr{7nfAabLreVczN+xs!M#S$=qN0yR-v>0 zXJFWD($~$i4Wf-L;vc=Yz8okl*Bi>e)euObVep-Ly;f_SYt(A>x@d^vB-A$J@-IO| z-Rk=@E34XEedog7*Vj4nn;npC$>mm>lb-iy^+t1keqnyT*>LoM*9BMKKdt}rFaPqV zKJ}>x-#@EA_Sosur%#?ddGEbf!DsEKc0x!$IU8pUh3Jdn>(4blN_<<0&bc;6iwZ1HVPWy>4?Rl2}2TmcB|D5BMyOL0tXe^U_{jlR9G}nU81^0wDeks-nAz6Yl?T2p12x5fIwH+xju&kmytRu;su1?p*F{5`X>w z0w%$n4D*BE%R!%2LOuEXq~(7A5m-O~{_jp!E1~=f|L>d&|A&iu|N3$355updu#c_( z6%XN$f3mirs28>8?wl;N=l!3LA=88nMF>wnv)r2MUB2=MicoVTvo5#i{gJEg-oGq3 zK{BCE9(7U0odksOKcdGA6BCU;>cA~~p|D^nJIgB=AlLuBW-b@h-aO-(wL5X~778+7 zy}DTGCuM~HLqofr%-JS%;)-?RE*8b3n2UE}iYH^&-kT{&Tv}aWqbqE7g{`iz-4%Aa zLddFif@Qi*w9{JL4d3j_KOV)q3x@oPlcRjmccv?Z`DY@f4&$3q{_uM|Opp3omMRr` z!f`Z8OpK$9t36S&%6G=qIQ6wi3fW;IB0Z(q4w2A{kNMSXv!QjyP*%TFp!7f_i3)?T4fsVwn{@_P%#%%epW5A!eD zeSV};nN@ZgLj5HPlKflG%goM}%Vdw*ulj$XFRnk6J*pNELVU8NMqbD-kzv%k{*&ZR zeyCysEcDiX6_3h$A>Cfs9is2~JK9F1u@+c;NJd z(SKs%AmOBwZ)@u8EPhWU53??Wd_`4eg&qNL6(9}95bM8Ywd7L6EAz1sO((gnTe~>> zV%9A-aacz+)-Jj!6gJ~aA(QFp>FXOB8XupTSz2nhgP_&g*x20M+S=aU*^#|pTAG;| zA0Ha(>+9*sWZLbWo$c+dt@s+R?`dvqlgQi$y~Ugp;^9}9Iy)) zD6)j4%*`#q)nmj8g_%ZfhT&K$LEM`um)(E)n3G5OuI9g5|K@VLzxdE2Po93{$$_l& zeFQzM%zms?LZSv0uYT@le(o~|{^paFN_9f`{(>QFj%&?d5ZC(@XNqyN9M_YqWd4PP z(4Zz06ZZ=XiAdLNsLOFGf|Cpm+{xs?olG&@nFKF_gGKXbi3t$PwISKwFyx)`iMk|0 z7VwQ*o;N?AfL-@?VQp>Ux&W8h8JaEL>dM*$rqXnVUK>+7Y28fBbisp#PF~$Pt?#6D z$2$jt|x7Bn3+=}gE<8eW(vbioI&ZKYrETQSZw+@JToRtoOSZDjtOQ|zPfhCp_4 z(lb*%<9TkP-0N+r4|gmBrF$5xhU4m(^lI>jNSD;xUnmsO)=6OmTj5geQpbk&jmok} z4M+Qwe`8d-DEmLUp|}NqJh}_NUDa`-<6|7Xrdtei2kdPm?(J5sG>64~2Qi$UV4&;n zAWuEeSuYsdUyBRaP4@LEmtX^V;-Z!&g9e^tNTZ2kk3JgT+RZc1q~l3{QIPI!SW!-nTm|fExqn{R7A0h%qKP`~N-h_TLjY5WVBnF^JNIb)+ z22zS+JXJhyf0yY57)oHNT5Ybafx=%~YgVfzefs-Bk?Zdl%n=N7s<>WAw7&!H@Zg&E zcR-GSt-M?6snuGY@;%o2Y<6G4mGAI3=wxztTbt&#CJE7o2IYNOXtnf}vLpM-H9~nG z>utRQrAmDn_85aSuhs-QlQB)xz(Wx6TS8*{8=bMhC8e(PhM!94iWDo2MpsfQIyrap zF0;R(3Y~o>)TB)2nX}}CxFJApYG?7n76X#g6XMyvfl_HeyB($7J@jC$b*4#EH|Cqo z`HdPG6x2$#M|yHD>Tk@e@y-omY}9-(`_X%kYfRX*1;b75vMZ{8N_zo~sqXP-46nCR z88h)8g1~HcTr0VvH@~CB`@;4%ohJXQQ0U)1QkkvQj#v*G-(m5k+GUDc&;kY|hA}T# zUE2sY)>Z>cz-Tf!SF6LAQYBzizxH^e@x~c9{z85aV=*ARcpC*TSOEP7By1?Z4EHoT zl*{+uI_m72KaC|XtTyj9kwLR(Q1iZ_-D8+%)BBxmCNO8G#%K@KN8`T{K=sl1kF5tj zWHTe11r0$(Ytv>%HVfJme6X;;${tj+x<4xadbLETzHa41#=7B}t~bS&y)-q4d|90t z(904DE~~`U3ko+{0katib`+M7@6guS7hZ@>w&Dx$RDeH@L$D`bF#W`|)O?x#d@gii z;yGXlk7s}epNZ#MhRoX$CgYi845g3fh9NvTJ0z)GWP~|#ga#MO%CWMFeY?PVsGoxr4Tt^2?$Ck z_Q&DUCFZxl#oNx8V=!^CnJ<+|2AdNn68g~GMASQT#`lx)@V>9hLEPAgGWEr3<5I%8 zO$4^@*hI&vs7S{<^wMzo-)T6-P|wbC-k=0O3Rzm1(IpPSLI9)aK&6E8spXCN1sE0D zUniyF(719X!j=qj6iBDn$=oLa9Y(hUGt3(Z9b&eja-Jp~heq3s2c)~yu@>ob4zN~)35D^e2$M6tAgkSX=hL8Z+N(j@#kF7XsQnSVi~m8Op(*^RylX(QG&nfyE1G*_amN5>xe8>~qu_aC3l}G& z@{<=A#-@6YM7x8z!6Us>D&Gla9iqbaO}Dt=+8C1GW^{7HwY9M@(<$rjtO=$c;qb={ z$Z1cc2_5v;NC|~|#uh>p?rUSroRm%)q8;h5d9bK&p|G|PswlGMPZmb=gSp-;J}AX@ zu8~hw8-0XV3L1U5#m`MbJ2{*KY^qhRm*GPe{3}uO0;$-F7XiX-ly-n9o6s4Tiy!^e z?!g@9Tzs>{_%i0#YO}L)23^qhE9|DPT)5VM7mkkq-tpXBen+_T;${2k0SCzTuwQMr zl$Q(z-flKNFoj4M8B1f{6wa?Nol~kE{BhcglyZh9=fU@#np+t%?*(iujtJ?JA?A{G ziz5*@gaZz9I5^-ahb9;L#0c0q50NNI)1PRPLv0%*G5v9q9Q`Z^$B#C>2M7b2l zQTN-arP+M09eK;}CxdmTX+tQmdJm>>@%>FWKv`C8=jKk{y^C2wr9NxZJE6SDnTgY< zFWPoa-wZoKb`gL4quU$d#Wyg#-PJ1<=BlEEjmgQ$g;rqq@r6Bt-5&1q#@AoGxU#ak z78pE}8_Ic3w3Rbxt!=FZ@f;h`0!|B*OTBFHmdn)=2E1Q(7y3diq-rSa1gtrv;~eNJ z{Dd=`YqFr5Tnb)KPdNGCH*Na|!RF55ZnIWdO9AY1#PG$hyz6p=DGn)D_Cb2QPSrje z9D(d}XmC>Yml{I*>`&cMwnF7QrhJFX=En<^Rq&^#XIz+$;Tu~!TN{Ca?b0(i884A$ zci(lz=)ZE;?rfN)XJ|%K4-47d)1iky9m4^1M%dih(TQf@GV7|578&XaL33jCY|h~O zMn_85!eu@T?h0l~BcuC#-D@PT1-grZ^d`@an)6g6;cZ7?6bn@jl?!?%C*Ed!eVgT2 z%aQFJ81`%a@IY_WT(6BZM8(yxeXc`U=XKWWXw*v^UbOU+-RD}l5rK|gL#ESj_M;AA zIvB-Tj=-2O7c~b=#)ac`YLKSZk~ESu3AF_TpdAcR$Ara$WC+U}D3cu=56erU0`BF( z(mq}JIQ$!`yAWPUC0O68tb)IA$(pFyw@+NUk-udSQeAoBG#6M{xV6#0Z%`B){Q@W9 z5njv6W!qZjV`c(kRynp;TXntq zzbW2%_`ydWdGPR^q5re`_K)6u@4a__^!BQzA%i1#r8&H?7LEuA1^5+)y5+m&ugy<7 zn87u%P6p=KXF72Bo6?Y=7LVRmh$*^F%_9t$Kr;<4?%XSFL)n&z*=Ed>_@$m5;)av5 z?n*r59GeU_$M86o8p&6$sAT)W;SKj6TuCc#=U4F$ox`QWROIZ&Z~gCW7!KVh;gaVh zT$$(}x{6RR_fh_*k{L1F`isfF=3fc`93|l-PC2_mQv8Dy%n6A@WLMKb!`C0SlKi3C z(g)7|xcWNnPoh*?Mn^fm$#P4v=;#ZNb5D z{4PVy$RzF-Hl32_elx0=dy~Z(*{FDlJo3uT111aYlVKl%W+a0+^^Q*XEyM#8M0|I) zr*};LiyBVcYw_6-Km6(xx3rHCp3fq_wL%M5G=C)!cg_`U-_^5glxWNHL*%NnpBy`K z5)$eM=YyRFhWh7F$VR*MNyVvt69OjR^sR)oL1{F{@aXYx(6IAqF(Zc3DYBf1H{waD#x zo&F0JOb}ZUIQ+IR*t)?-VIfL4Axn&5sy&oH%hIi+vG#`uXxy${yRy-E>T%|OetzEf zWBhcSypSj^53q&-h~kk6$b^DsHlo()egwpoJj#ea!ot;%!UnpN8jtbtMTWlQmqH#R8QEcBAIk>`shHz*k?eeu&@@y5FQ_ zqEG;ddeZi{Y?z~b7reBml!n821*S#Ld~VS%mcm8LI9>4U|5HlAGt|i#Zx+~10$z822;9f2dbR+qF#Xo9BZqC41sXZ@8g1S5o$O)eXh+*I*2JPZ3$a8;Yh_OSseHzPC+)2)D8LvRhedUC}}z@29j4*Czvx_AADd{p zoF5#JuM*kcG#vJI!KdkI@z0g#F~(k(AuKPR(!CiL0hXl8ytP$?xjDJ(^(&_vUI|PvHiE zmx1hC#y;yjB&l$4R`Q)Yt88(|O9k|Jt%V>u-eC>&$~wC^=~pBvUO?*`bwZ=L3Hn4} z2_hV8f&dV1;#vZ#Z9r{MknX0C8!xT^X3aq@8P?GVp$ETibOgBcXmY` z!i@A<{5-O127>Zr9KwU>`2eT4JM!Ue4$6SI12M3SB^Wv2gQao}(rbZ?_v-uxk1c!? zU}oH`Cq6_dKO0`~$%R&pyc#Ohmk@G`nA zXINqhSZg*w5W%gBXlUeLVtuz|f}MYs^1pifZ`+;pzqmtg!xCMJ$p)F<&OTee}n$s>Z_QA?e}?l?Aqta{$o>IJqVG7$c^64aTuW%1WLqx zae+}(4cpG;*DkeCgD^S#vWM5BBz292C?W1ax&pJ(f;AQ*IJ0lvBEJMmYJH5S{{qQR zMvD(hkKo%9U0f1_J3#0qM(sedta{leXW&4SS#o(1Iu~qs4ew2jtlyNtqq>g9mSW-n zZI?D!cWy6)YsmhFqtE;cX_K!U@e!k34*3=R3Ao&Y=m=5-x83cS%`CA%`%Vz@hw>>n z4r~gp8p4?+=Mcp_o!y9>Z;_LNXMb}!4VV7mJp0ON%Ep)Z@1c5i!>s|PJ5GGbKCYq) z;Z3->sZ%7$WCy2w8ctWr!^|lw{V&w1`9m5m|2GZyMk%Tf#iJvTCLIxdUGO~KT?!rv zP1MDkP(b4`GJ3$&4W5QwA^`bmxJcIoj*xZY>rGz?MM2^xKmsoIrQm8YuD>d9vse{K z(U*c#z8kLoHN%(ae>TwP1HpMMGHJJmb>h^aeLj*z}IJiF_?G#vS5c(5xM zRY(XI>2+(6BwX^5fGdx2Csd<=U=Dx)E{FmJ$3z>|EFRhyfh8IV`I2r)zJQ?KR-Qdf zD})Ab%0hnqqG}40+*gmCAkg5S(r@w0l4?J&$*-|+9k`yVwT%~L5IkmEDF5zo5e;(U(*;L9%>3U7j(5!ok(B;; zJipQzQdJ{Pnpzm~rwdL4ZVHD%I(^wGPrn=gP5kLJPG7FAvP>TJUlNY~-4yOU^X#)- zi#ruHOg8$sA;`ujfo5DO zD{swnEN&^;Zm$Cf;?4@0hDj{WtZm&|aDE*uN5ng#Xlw`k69EOrY+hf28$?lz#**Vvq%H1W$FKx;`=f zD?@txPmg~pZ_*O+SBjS$zwE69sqx7;XUCg-sE}Iu%#XHY!HFmLPbKObw)XAjrxJAs z?+Cf69O-dz=+#|z{yju5pT*9|kso#ur!65mv}1qL?r?}Y!x`{QnZ_)ay+ zmUn47HNPzdwP8ep8wZCrbydrF7nN3=Oo^jm#Z0_%I?@25P#yLWcl_hY=*|W?*`xOz zv7W!OLY(LEMy|6zz8dY1JI!$-qI+jK9hY=}v;FTD@EOq^1(kOUb64U?{!4wr{^iaE z9q`0*OUAALT+M+2b?@kNd3B8+9Y9F};v7!o+6f$96vPEfrUfXY>m4zWg%NELv&7lO7Jy;ptAp5D2ci^#*|O49wIyoj>Cp0Pgt|YR_ebqg)yk z{VfFDpK3t=D=&(EJ3RA&eWKsNdAY#Gzy1T!|Dw@P6EPd=#k;?YmpwEP1JeXfXv&}%VO z<^xI^rAFGf#=T3m!1A^HXaw{IhgEkt$O3ditP#$&&6x+oZy+ozz?PxW#g*>VZ-B(| z04E4`_p`rY>0Bn80asgow;@v$Lcl1A*f&Cp4-YgGw;+}g_C`*PT3@TZF&V*awJ+bl zFNzy^VKc?OT$a^Wxo1Nxc?Fwf)2G7#9b!TU;?Ye);Fdoe#-WnPGy0T}-=ub&%moMK zYUHy48xEkxq|WlHR_K!W^IP5c?fofn{qA@UG7#aXZZRP4-$|(J^qwuu>-Q~ zP^_)4c4i406(wKn5EmRqX_t^kEf^f(>9a)nCI%qczbF%j@Arr91q@hOS%D%kQNhGZ z`Wv1Cb>bss#=H(!Cr+^$KR;0&2D~x)cImm_RCuoR_UMMe51s~m>ZfA(pBy-F{5N;~ z+a&zd{ON;9_#YlP@Fy{RV*b>rk05r$%@7k3rfAI9_kDpHA zPs4voq#*QAHo*Abvw|74O&Yx`^9ox5WdPn1ohKmi-j*DT!n z^M#W~YO}TSXrH&e_0-_wkMBD9Oy)vnc~Anjix+3|GNb0Kd%r<|;QMPYtY7AJH5-5l z_@**P{*sG&Z7C~Bk$94fgbElgP(^EWwLpo4-VD!}@f|N<1vXB`@X(2h-jKry1ndt+ zBGh-O=Pq4xR*Rvu3839^p}aW((NlkvcL<^kA;qD3lImk2ut*M$>i4s&l(10I4BmMY zu?w70BNR5xK*aQ8Ay8ol3a>U!$0_tYEGvZb8(U#v3cV5pVGcsF>$uwdEV0P3h#I{>e$VsM8AJ47HLQ9nV1KNHq6uZIjN$NhA)0 ztNO)l56iz}MSPa=O!TrY)n@ zn)NF3XDS!9-!zu|;q2MzW#mp`DY{p zEQDOn%-4*I#n*2CURo{>9p_|N<7;TkU{Vm4`HT7Y^m-gbi?uVnNWQF{3D?KPN53Dn zKQ7FT$|E&#V0iIv2In~lZ&A7(c5>`rZP8*(o@Cib2|GbH!a9DX!G3qOu|nMFNXS1) zp^`cON|J5zi@A~ZyZH$%3+316U`M4gU8$7ICjV@%TICE8t7phBzgf-KG-Q;xlfUg1 zql0*N;0Mg-!PrUrj%9In=-T~9htMOi zMxey{zCCz56Fr6-K6ne~-2=K|`V5Yo-G=Gg@dLU}<~Uk(+1rMHEiq8ZEPKW9 z7LtQ_#&GeKFvEk25SJ{k9%va*mxUvLX?L&F4(yDOgh4Oju>)v)%fC@vn+MxrJj!Pq zH^!kT1rH(QQ0fs&hH}Ey(0vFqx1&PcabtYq(v>fY#yPsnNAV~_R3Q2e)4S`Bz^>!T z6eqZwIDdpU`VRBO@F;#Gc$ki-yuPP;r?xgDv&x!2%(>H-1>DOz|u3vuO_JarK&iC`c;q~E9^EQ(s{rxvAf7i*`*(Z4C!Hw`g zjjzLEd8u>*{CAz4n>%uo@`B&fRsP=Dxr2Aa?Y9>Ur|M6_OLxJ&o0h+pf64OVZ#Vyv z@ayp}35S1Az=0dmcNhHa=3lD(b@-QrUypy?@Ff4r`;Q-=dvKOhR8GEBe(sMu{nrgQ z{ypF6zizn6-^=A#{;mf<@@xlx<&KjlPd`$xRKohZ`PW_E_?IZ(4LA9_3H_44;!WvC z{%%s<_?swyc%u2h?2Y8_KlZ%re{T8X*Yhp0N6AYvZ1eVlf^Ff-erYa1@NJ8CL+{oz zCg>G=X5R#7{XHzNhfDODbG_$W@bLA2-Q{i36Z_?+Zg`ydZuXuVTr(GJEz$itfNfuC zDGsZAv|g|4iDF!0i|ff|O_8JW1wENaS_C&|S(h;XS*8v-URmrr{J50(5IA$3{#O~B zxYTGX^8?{Dr!|wDpOb^>=_WPU^T~F!Px+!C-!ljUX`{Dwjt_vpb~;PS4AMAiSYNtC|a60b{=ex(@jj` zSf#P5caOz!_iC3;v~wr_rc$pTt9R`GRo)fxz1gz!526D;of4a!TkiBqRi00Y(}J4G zR~(mWB~=Le^&i9ShF1%xxE!=vK{`hm>&j&l%yh=EXW~R#IZ5y@sQErJ7{lF-!`s0w z=D|V%UE+Au%CP&kb%KCh`VO3iYN8v#Q88-Su=y`K5SMSc<|oR#3iN&yx4zsm*|0T| z4ToO#%k4o5RD;Ft?N+%Q^g&<}4&%~rbwILw%}>Ft{}OQ4e9~}4FIgVtOu_Z$%Osrk zrQinCVmWr)_aWE4S;9TOq4k~g{)Rc&q!Ks|u~BOw7`8a?E=srK6<$lXwpW!&!D+t< zXauMEDY(}KXU#DMr+umN)E`X^_*SKXE^(mkDR>Y=+zqQ{DLC9q<)Ho)T;?SejJo`^ z#N&GJx9Q0x52$$_+hZ1@^J$Qr8Xtn7)-^t4QgHZ}hSNUx1|DZW(VrAt;+2FWKPfoI zKLv-sDR{JhR<4ZXNA}b5D|hGFjbDlOSD@cDh^y2X`s27;|IWm5!J$8nyYoNUIBw-@ zejFDZ`r^3Y3k#iigx@@#uv3KJJSJ0g5*at$>aMOXQ)ly*xGfF4&HH|>Cu``&259s) zGbou76QlhB8rZczfCMJs5Rir&Fj2ndr{QRLvb@Kx)JD?3kpw32Ylk-pHw90?QScNT z@);uv{Og2X7^YrdW}oHCA4KtZ{TdD{aDI$X*a!l801l+~7ra1BLJJ-LVNVJ!1|;Ed zE(Mo{CE*?oOyQ@ClkoJ=Bf0{l%mu|%e=?~46ddj)0~(TsBVwsQ{fY9N8q4%XFPI@8 z3#+Y~UNGQC!xSBu^#4$C(QiR`L;fMfl3#@&gqwU3H~z)&kbjZGws%~4(U0m77)mSz9)$_c{}%m8xad#8;eQe? z{-@yZKM9wLr{L7-Hb*p8VF7BYAMW#QAPRTy&)E8YB%X%fcG#`F!ylKYPm<#!E`hf)PD z7dDWvFjxZc6n}xI_zQ(8{R5uVKhMEwLnyxv4vJ8|#6I_WPv0XL``r1NUYXuVY6Mfw zVJR1Nq|tqxK#ccKg9wKIk#VHEE0l10HG;BNuiK1H0O;VMU64NbM++u(iUsu9G#sHx z!A-N>#*xbN0#|!~Tqr<60QLBWoq*D7Up>iR+qFVV^V%OnI`smTz)C6cnD{psHEJdqv(`En&>pVarR z|68O63z8A_WLNic{wHj^E6Pw`r zioQ)p1&ZcW-m=-{>wc{hu{+VHf>C)D?UWZFjo%B>@PvOWxeL%viJq_Xd#?3K`vT9> z_9fI!6L4BTnWWF;TZEZ8F;*{V^+SG&ho7@y_)~DGPr;q{?97k(r!qc}Y1gg77)Vq8 zwHhC1z&=HAqX0Gm*WgAp)a20*rruB3TD6?<`bhS+^!p2acQh=9!yBf!m~)UyiRmAy zF6?mUccS{8n{D-{_>22v73w1S#Qllm;t%-axZvQA<7S^z+Kr?ov|A!3UNAup4=^c4 z4|^NB2?JPD`e_`p-D52SP=9CmK+=M!Sn8WDBsg89hY=xxjXu+#B%B^j!Id**zllfo z+n;h8nuJq4hCBJR@*)5H+8UNUdjFen(|qUtxbs!^_?o#t@iIpy<^QxCej8#`T&+s_ zN1|UMq#!sP68&NQ)bO$&>$Et z=!Rb3;6qrbwWR&25Co|x+6nQ7&&_{oK8>?1;qy@uJf5Ff=N?7C?HGWQPbc2!b>QYd z;Q^RbRfeDELLKp3#UCUiHU5DhHNL@|Sl%W7l!@a`zCa-?vHU?nTE3$G$@N4n^h`c@ zJ)kJi+^N&QwM%MzvVVm?3Zg*xYf%V*7=A(YaqwV4IE0-*6O#R_CUo~-a{X3CqV?O6 zQN>sUHUuCF!x|m$OR| z?x?ug8HyNXnw!E$(-ooI;@KHz<`j#9y>G@Mj(x3K2r<4zxx83>sp^bNP3o7L9_hDU zw4~t9w?(JTtPilrzVBX`M;An=bVCjmCA%P3xOoC)uR0&g0PvE zOHM8~1iw}bYBk??_DdlYd;2r%?OtP(B(C;i*G?eGg^J6O(E`BlB zYj8;iPo>81UmcyO34=)&r)2nftHk&O_2_ThKI{74P8$srH4y9ucU0Kb;L(o+l44Cu z&~Mf&qTiL10p#_?W*w9QG|%C@j;F6)Ny@)g7j1=+^aOruUjo0iPY9Fa!)O(`OpiaI z_HxL~I5bu^T(4R{a;u0RL#g04t=82Rl5NuBmXKm3cN%Q(Cl_P>=EJXxMj zWCRKAJ2`MrcuJ;&U;Ve)=^w!n-VS`j&abBGhr}DhO+KI?Y9!@_Jw`y3aIJhB@m%&L z#($-qg}y}l#&kN;*%&Kv#zzCa4*N*Ni-`48`dh21Lo7EJwLjTDwLgJBDPLA3vX4=D zC;zejh5FUuZ#K*8XG43UGQQ6PW1R60%fq`A`&7Bv2Plm6Gt!SpKO_B!^fLuVKO?wR zVVTgsXsDGEv4pb`)*sJrBDm~t67KSu{gw2F!N!+_e&+Zg4Cfj+{&hI0^OwD`{v)5& zb1w`#`7-HGtUuB<8lMyEkK{2oSM}G%S@f2L;)BL4;hrg;h1-J4EIOx=e zOtDRWTQ#|Nd2a)6WfPb}624Hg;Uk9g^TL)Vy4e0~6uI_0P`EbvdMTZ(Y9c|8Ut8E{ zfrIB1Ho|xa4`axn;4UPsl2SS{8D>a)g+GuSr`Y+b@ZC*OqMF|o9C2adHSkC;qe2_e zjr;B<9oeWQbM$tMswLAs9jAkogwZv40nN3W=tAE`xB3oher)v=Z|jl>#`MHRpk$r| z$Zn&eQJx#YBQ!UGTU9rL%X~9p`8;06*?zo-FyKnK7Z`+uMCq$+piPW+JXV1dBZTD+ zYH41*A1~?XRA0A}Glc8lZ=tAGk-OMiR1$IIG!+Y1`Vwh^vpSy&3k#{J#=T?*)BQC+ zm7^2UB&HL)_D*V^OqG?hcr+};z@XN7wlYq9Us^GvDg0jS--bAt2PLq19t)T^fOK&_ zDwR?;L}@bu=sN`@t`Sn{aY$zX+69j@+KsuWsU#-psrY8c!Lani0}K|&$4cg>xE#bd zP<-=!Sr+GxZqA|s(LLWf-!-krucPx{Tic6^7GGQp&wovSjQHaDj~%u1Wn0_R-+k+~ zCC-QKOTw4Ve{8w~e{1Hgx4t_apC4O1fBtL-|2L*zd+oKM*S_(M5PtMy=g%!A%J180 zQ@m4t`eWzMpF5w#-&Teg|IrzvH$1<#wY?AeUVCjRLI3&lP;f)~gr6qIvePj4Lzw^#JH^l#g zZ~cRR@cF)Xe(-}El;6F$H2%&_%D?ovrKRzk(7*c!??B+q=>PoZf9EFU#h>4K>#ewd z@A>fJ;`uNA#z!VY{(b8o{Vxjt=v$)y+90Je-3rw!n`LDn49e~M`naID#5uC+ipy)p zb+!<}?cuM4;PdPzKky(-F5m^Q%o@ea3-B@iL6o8e>*)6(RG&ROmcYlWh4}@UTu%8b z70g3Acl3y63GI?At?tXyJ39K|*AV0~l7)hNzD-HGRS zWqCP=ulz>eD#S6uMdkhCKyIMu*Ay?6s9!(OTv|Vk{_E$d>a}By#(sA`l=Gigi^U%n zk9^x+kN~_=sntwWYn-3&oPXm{ z+Ls?Kmmj;FD1RbdzWBpT@oKU>GYUV#|Jd?{@7ej*PWk$5tyBNEIe&iSUv=mU>5tDp zhxEti!oRYd&48Zsvl0FfUeWJ!ZHzYR*~~1VUSApA5dVZ91|{(qAH6VJiO%0& zgMV4*6Zn7Xex6lpPDJg?-u1`N5}u3OUxE9a-;3e&kIvV}@G{)(;$Jbzf0Y+~C8Ix= zy+ZGmzlp=-=%@cFJ{z?^m%U8yJo<8_QVrqP)NiYu$@1{O7N2hfzXT*9AG62cS4TdO zA24LEMD>e*^-lj~IiE-m#`5P^dEfVJg1(Y|F?P1oKNHQy@#6{pKlkkOr%shCl@9({ zB(NIuuTq}9!1>2c`=P$m|2gV^`Q;@3{Xl2y3H_jaCKJo&ohBc%& zhWztq?@i*bTepJ{&IaeE`N;TwZk#}+3yL#dma2IL|@##O6A9o zzFaO>9t+Et%O_xey;9Wz71OV5R``phCzJS3#PXk8zIx%p|N2ej+reRWy)OEE_x_z+ z_Fa(|)5q;G2aoapxJ(Ci=okNLwGRJOzF2%WqQ6pkuwGB_ANo_}E9F{4aQl6Eqd%kP zZs0^R`+%I zzuYyxlq*2d|44tXRLp+G@^A23J=PE451|7cPA7CiK6{_<3{spMU<*o0J!S9xaz6`+uG19~002A-U-gx$gE2$gN$6SK@v$ z5XVvN1mcnF9{KNbRN;meyluLy%-mhNbP1Vp<+V1BQFQ*h15-)pzpEH&_VaGcByip3 zyswf(ATDyiAOHU2D+Ikf#sY9eakdh=@5*m&k1oU`(%7CT;#t#Pn_94X4^_mq^^leK zt^;0*v%+ZJJMO#u`*3Q(>OTPD_Pd?5Xk~@p8zVm2o8f;7^N?grb52}A(P76vH}@R4UUj+bc7~YlD3@+Y(SiTVbseO z_mwKDh+p3*?w#_2U-YJ3#bgQs(O=+)kh)efJg?@fy$k&IafaW!0i2~DE5|6r7MESg z6L3?QX!JnU(dy%Sl)n&Gmm3-R&YnA9fVDKoyP;Hz=&QZb&`c+!&zmWinHeRh@K0A9 zr>&MkVNn&|D?G-pkTU???iy3Ci2jUN7+5j=Oy0V7|KZ=0Y|M4=FBBvGxr~`TrAm3$ z^MCq_)d~NDti1cJ86dgbGkf#`qN(1|9GBccb>bjiUep{fYF{RM`++)rTg>|)9`ypm zb{Z;-H?9V*pZXh4;-ZA^_?S$5t@8`@|M1_q2`2dk;FnmMXPS7?QTYVilDhGIa6eMN z|AYMIz0||^%a!U>6|)+Z@4#J(ejUD6>zohoj(5&i^!DqRU39*J(&5y3pvWs!YsA;r z=`RcGnxEcu@chpJ$oqj09XfP-ehF*T-#_3D4&>Xb&p!L-zx(Q|uN*jem*=JQ9{%v? z64&d7N-cr(0`$PCiBDD*?Ne-SU!wQ{gA)&KeL zf99)S{p#Pl^q*Y*8JDs>yEr?95!UgcpvJ(!0f|d3^-1uby#Du7VeCUE$gn1ZJKw4l zEshoJ1)iJ)x5ta*aR7fm{C`n6RrmDtk4;aH_4n9boqinsjo+T0{_QuSA4wm7?D)x3 zwPOq8A?Z7r9k?3=7DXD^$)9I@DGc+^ne-L?>A&r*s8e{hlRd5D?9J=v*n-s+d$$Ma z!2<6)<-I}byF&5Sv!GyqV7le;+8h7B|InuY^2@&id8uG^CNDt8`ONTH;=@DS>^Y2X z@JeaEEr{tNeaT|>>lk)~JtRY*5Qa4f&(wEbKY~>&mhM*jaCmuvQV_JsqxVybw6^pE z_$lDZG2%_FuCUm-jkc|<~8ZbiSUD=Vw3 zFRZ_OskL0627iBP&*VJ6Kc`Uif-U5DV{PylF52iq0R01{(p{9d0R4K=%2VP_3`~V~G z*0tp#^G0VYKMen9yYkTf)v>E#8;w6H`fz}GXV-iDKlj{oeC_u7`)?_Y9641ShkgVc zS=phF8r61=kNTJXp?;7Xf%elt+w^_gUZl9K`u7%&oPvL%@K*7+P4B$=>M42HJ>c&z zjTrsbh2Vcji>E(+_Sw0)gQx@i-CLyoy`TpPZyw9P1rgK_Sb;>)Q@jD`El^WUfQ?13hPb2+WdkG@;Nk6Qh72A)5SE8cZZxj`Ns&rKW6|j z{3FmuhP~uLZL6g^>cfBA`WO7e$OqQN>Tj&JX<(ZsuD$re`WpNjD(?NcPwd&Vw>S=q zpy&JJ-+t`dryu%G{`-TaN2x!*7ygKQdqkh7;_ExP*B^Q4JFn$(UO)0zocwq(>_9KK zy2J02>{P#I9k{Lj*<1L?LnC{Od-mLhe(-LPH)h^w-v6DE7arPk;Dq|8v={k?JOy5# zn#;B;uU2;GfBw8Zd&UnOnE3p}G+xrrl=tJ0zd2s1Tv>kQ1(c{VEB={&xbl0&fBNP< zOrXk3Kl=BU9DgK3UTr(yZv3rtoLM;M?JV!mKGpwm_@_VQw_UBYE5H8guiIxg{eMeg z&qp5Kvu9*aVK4F%v~ydz_V0ahn^v~h=Wx$*qmN~CGi*`Wd}o7Iu>FOtTn<4kmobjx zycX_^ej{d_3}dNilfEnU(jBGVy#H<&4T>TQj+#k;nOkZvB3l?B`}- zYw(sWho4m8Mmfg4a9-zB8{XOPpYcxMJM9rxoe{={BfIYw3Y+#{Xfqwu(JRELP%Kv( z9{fY>{=F1j^1A{27TVZ{71yFi2Dti{&aGCdXUy}CAK1g(de@#k2PcjGD zUYAH0>4%e+5WaHd0s6;{J5fBB+e7%7YC}JA*LThpuUvi%9Q?$?Zg%d5&hF~H$9>(l z0Q@r8AG^wBIa~jhNAc=Ff1&EW1XtxMU&&^dAE3|1QM{Qdf6!2l@LwimuV6pDnan_L zrV3pD$p2cQuw?63FTecqH^1T)#*3AuYIR~}fN`Q+({y}MbHB@#`d2hQP%j`_Gjj?9 zGX#8XZK?RLipA$omCKjE1%BpZUt}PdIdtf!jxzrysO`n)pMUv#^{>GG+Nb$rnr(m7 zzqZ!4_hXe=A_7iw1PtqU<+TI_ytq^xhyEGZHzWQ*{}Q;L=LJD8m#;j4e$KGkzTc}X zq2P!9D*nr%L;BCJtiJlYfAS3ejeZ%&e~^x(rz}VSuJF04{!hSr)Z2s*{@8L1FI7(D zM|jM}Wf1&orNaJ%e&2BhL9gB^t*h?$XDA&6FMfY@^~FH$BV$!Y>Q$r>`6VF_Om$5^ z+lX=KUdeT`pe)-M5uE5rI~#AQ=wSE{SmU3TcaSq`;HBMg79N)GnDTv^NF)r0S>vMB z<`~j%ZF=GTb2QVc2498!zmw-r3M0-yKiCjq1!F_&tf&UX*KZ;qb(L z%nx_?^~G(5hwa+V>GyhZ+0JSr@*tnHB7Uj`+S-y`XJ==CKh50nQbR zMc5I4pT6IfcLbUNlQzGL0Z@mYy)UMp1Ar6{{jcWASKd|qUurg?o=i{SL9?!-;VYEk zTUnOMW|!1Jg>&v_7{9AuQ?T$-5b;OtJ8S2E+UA>MCH|J)@r-R${c|G0_?KH@0K`Jd zO(9Uf_Y^?#2rT-}tu`k=``;ET-yYNhJd*z+^1q}9?eJGn0N6Y2wR5jG8n4s7%+lQ4 zgL8BD-S=1I@OkxRn*MF=-Jj++Mc}u0wmEm-{Zw%B=?u@1nEl=_C4>VBkCG)N`jiW1~-TDp2p=rv|`*HVbdxg=^pC zdmjAG8J!~!@*(>h`8VZ*_x!2(*P8xLTeD~v_o=umABvZi&%%JVVSP%^#5ivk7C&I} zW5arGJ7|~7r=EQm`BncKflo8Si2m)>GpjostsY&-YAzGf2LqmFjaBk5{oucyIrS># z`;hp#STAJE8cuZI4S*Z0(ere5$*>ch&)JEzV6YBs;~*es)G=1Z!7 z?!E_}<_)S|zMVJxUYqtye`(-@YQV{pU*btI+CS~L2ip0qxqtJ}-&lW4`d_4%mvW=B z>fE7j=hjx+g~28C?i}=GpL+2AlL)}v183>q-9K7sw#&bDK42bo=3h`D@@?9G-_yJF ze1Gj+ZKt+fM?mlT&e4B93H+%C#C{m$+Bbjk3-IsN$bSPqXAM;QXn@i8+;cyl-LVVZ zJDwRr_LodVrop$x1EiZ6sdJEej*0yj_2VcHfBKZxS2FmIORLj|zVYhfq1?`g2c4^<~)1O|&f6d)i_+WwY^-g|3Z%7LEiz~ml(%4yk zH`u||*z$U^Pv19p@`1UNCm(!j*RG5w>rfhb?eXbX9{ouz#n|*nB7RCi3qrzqkDEGHBi{-6i=@AlbqamMnyYXjFL>cgx)jIGP#pTUt8Hv=<@e6O0Qptuiibs_WKY0ZTxk_uW(Mo zE&LOI1~(BpCQkgdwLYc(KgXw7{NSU4%P#7pznb9ShkUO4ej}H6^0iZGywhlW{&hSc z5AueeX6jWK9{UZT9`+IITiL1Z>}uy$kS|Iu@+s|m((HSoUDzqLOFK-_(XrnWe}%s^ zJVy6qGS|!>@sCDI<7nVgX<=M*iS3maUfD*&+SR|!C_?-87QUqF3%C6Wzi9{tF zB;L;H)9@eBKMVcC;xF>KZ^K&n>W)t?=8wROXDJT;Uy=JpGCvxh`HA1ozIJ)Nm--9C z+QEVWbTRhxD2rQLmBok7J+$-ctD=8=!*RHh9egs|H^!ST&U#WSJeL{0MWV$U!Ly6m zrF{S4gNL8U4c*;y&cl&y2j4yY-BbV4-*P)$OPSuY<7y_H+E4j*ZE|RP<0rVG>h0gV|=gn=ucPuc$zOG}(3V0ICPR41;Dxf_B(JT#gn7UTwDKMN zl+P|NUtWKX$>R&J{KkH6F!-QYu3-j|kYcTnthaOsAXFW5d-_>vUmw7bl;^s^I z6|p}_xXRb7JEfBRPZp(qi}f4_@6fO2pJQIGacFt@8Le+7=$obgCMG6+0DV8;d&1T? z41VB%Yd@sfx<)&rhDPll-hbf0`CB+N%{F4h`*815J z6X*j64xYb7^Fyy)@E6&bt}o_KKHJawUw{4<2&hy;`aq0)mVeKa6{xU2Bl?Du{9*0t zVYTrezxt1t1$X>8a7Wnx?|kNe_{{IJ%C)+~pX}dwd4{38x_3AGv19W0Y3{d6>!nh5 zxsJodu6TBwq>^4TkA2YW0Sk+X<^}dzcBu?^lqL%bD784#`iRV+AI{_Z8RtS!YTvC_`t52@}Xg# z(!Vv+bJUx9lM$x$>i11QCmEj!=NRKYc!o>iXT4gjx$=!GHS0q8uc8n0WAa%-zR|13 zm%Vee6B&Ykexd(fzu5Z(7HGIIaRU9^Sv_-czm~Ub{K@5(azpj%_yP+NT7Oc*R!>*A zo(XpB2bcuUEoEnzZ7_eG@fd&kud)1i&c^S-Gs7Amr#^C;H8$k^?AkVS50J~qm&c9& zupj2ncq7$gG@toxv#BZWYGYu_>_7Iobo&=Z_KX%jBK_6?Q@i-Cqt726$R4Zk^OM6P z2PSGKu7Qg`5^x0$5{kdfy!Bbxmj9&YSr?cSYW8=N+4E*$(>Q=Vr+qk%OwJ0Nx~Bc@ z!c>c42H#PE^9t3)pE@+nzxVJ%HP(mkf49)Cp8Oy4leS;O_{93ui84we&j8 zKEZC5x2V4mZ|(%aqL&{jeW*6Q9|P~}kM?oe@xS>Yrz`3N;DyRaf9Z~=`X>&}&EXHJ zQJT`Rg~5EB_0<%-AN*LqX7eBTi?2_N{_+L*TWN$#LdIV)YabsIU*wmt1QRv2=^0z- z@v0Tst_s^N`PDt2Sq3WY9?v7AYCifW?cQEpYhPNs_~k(DIkzh}Ff#R!jTnx<3H?An zS*b$?^80wq)ASRrqujpVx?~6N$5|dK?H$`&ts;H257%P8xqSi+*oMD!?YR+h-1a10 zT>P-$%gX_-A=W@(#%IT@QNk7tLF3>!YBpV{q#zd0D} zTzc_u1>!S*vk%rEX`E=BsD<(DyY=@fS1VU{dm|%DBV&16QDfdM{_ZSa_Hi#8Z%mCm zc7gigkT`>cYXKq%0^^Jbu=?e@x^U|#{FT7iD~x4GG(NL`vv-mWESCrQW%kbeL(*NV z1RAWE}wtg#{YiyFWA5_4@2d* z8=5+A=dtdZ&o9*)jYlxAk6>nNh{8^`Qh5&o^uba{JZ4Zb{XmJ6|8~F-7VIq7?S1x4 z*Zr$)(J=NIhAFn;USvWe1v*?gT&@1}ettvJ$=9XIw_kW6pZ`0OuNkZ! zQ^3QOLnlv`dc7Qm<+a>O^@R~`4fAIix7 z@zatph?yz&Wu=53u{=lxGmVFT+Uz4nmBDO;x19|J26wh8J9H#FctjH{ELVZ&!VvPt z3L6c$k7of;;2P5A+S5F#~wd-ShLbw+Q~O z^{<8Ao(w5NY7TH6jf9P5|S5!!XWxx1y3}hCHq|MN= z@dGLGRh{LI2juMfOjgQ0Es9osj%8 z`n9#UmD|n&$Gq(4<-| zf9b0S{|NrDuZME5Hskj9IQ6+xQ7^LnS04AUJ=`8ueA+jL*ubg5^V79jjo~5dmSb%F z9eoS!+v(HKJ!k8W$i346wh-0-=zrLITlSl@OAPam%<=#h=F!XdnE11$i!)Koz0GUCXkXx7qIUmKh@OqZrZQhanGZYx0&+E zRYZyRyVj#lqP;Hp0j%RKRa{%gHk1*Ra4-@a84*gb-ZyDdX_39 zOkqu4rm+W@9yjLJ7YmPn83vtW;B6dti>Wp|vP2t>k=P&Dwxqrv;#3kFh~!5o3AVh2 zd}9E7|FFK4YVuG2AX%Y&dD?%Hi7Slz93b@qI#=T|Ca6+czX(0qY`s$A7p_W`I{uV2 zCyHzT&@bjuk-jq^VZ_Em(X_^I>*8;SlqFFxf!m~y4|P;+Q(#SlnVHjw^CNVh8s@pEjeqDG7Jh-FKHKVrgGlPRo|+9>*uiXxh1@G##h-Fjp4Wm^^>=neJLoh zI`Tqp zNl=K zH~Y~nCny-e8K{iE`Tl}C!ZhsoEAwJ9&icR}%}>leO_!&A^n;nH{hv7ZdM>B)Elc;8 z?=Q_fYCQ<8i_4cQ>mwtpoY=&EmHJ`OVO$>_v%t~7E!@uiNFJ8c!+7r->c+F@LjKej zUtyi2HP!3D2sYSr2O5JOPN?T)U+048UYz8M4HA6+xd)qPk!AYVtv*z>{DS|H$!Kn) z=?#JPIa3g--U?Rdzjs@&*N=3ewz4sD54`;9+D?`U20!7ty7J{fj}K{AYTCgWKZ2Ua zZ?M1dCK)vU+0Pv27zQF!ES0JgvpW3gwd#+5_OsZ`#<3RNbW66rzm&a2=M>8iK;Mpu z&W=A(IP%Bnw-z5*LFM?-=mHDeI=}Qa<*B&!Blb^VajAGmO^Yl`8lMW^<#fj9OSU!;*_kX2&Cmy;O<@Ig&n?p>E>P(U9_u|%hi+nz2{@sD2-U9qMQ@HKl ze9G4MSU(#nl^4;${K=COyGI}Om{@D-xx?aHbM9I8TVdU7CELsSK-8-ae{k=oD|elI zh4_c^=p=Q?)kZ&J2lTr`d<2{X2U02wA;BYw?8&xP;d!w6;IZSsFpK!XC^zd5X9sR!5gq>({28sT+3G3&v`#hUMjy?vc54O# zH4bW%yLrJtVC#4J{J^0PO*ETWyHdr*m&N5={xuF4*@yMnL6(0a_$*DHm|)|9$*Y^c zO8@!_UnrG+cHSFde35^)(f_UH+#e5ljY`?eH4YYrC+7NZJJ{^s&H57N&1YzX^wTe_ zzRmhD^S}JC)`vcH@}$k*7+%}+fA>Sp-##?AI_V9}9O4fzg*k9>0R8x#^~upQU zK`R`@zc|>U|?TBF<8<9LC{n`^xm`0b1-xEWUvU@g+#kG$Bv zhaDbT7|k(#EO>o2pL3R22Kop6s%Zhv^dl$#6yJ;PneNZ;w)Gip9PnS@fW$2Ro5>?0 zc>-t6{Qqf8GvTV~mrcVouyN=sS|4F~M4?@?=XpK+&k?qdMw9{j8qjwyyz--0UQh<@ z-xT~~c}8EiNVM0Z6cZ%%vV!zanq5A?2Eg1L;sfOjLA+xMA(kI2{bm1;^<5Fcc&MSn zK86677zduiDZ1!WKmD29Ju4sLJc(D)X>%;%mt?cq~ez~@D`_)&U+J4O3o zO`8Ew2ChK)8D{E-@frzt`ab+)oO*A0+3i3uKPcpTG+)p$dC3?25%+PwEI9pYOcejx z?T4EA;xE%4^oz4amFg#LevDZyj!&|-kBINtGm8EoddLWWwMze%)@RhZVrkqzToVJO z`sl#a>*AsMZ*TFDPkzF72d-QG=mB>+kKyaUaq~Z#k%>Qj{HVqsju(9N!|Hxii1y{) zm{i}}{~aFcVfvBZeU{}jx)day>R-*#X}`UodV8`KkVHU3w7)b|EPdn`IY7q= zIxGv?S7>hEd;I@r>wSRZEbn{YcUNm`S61xZ)!LRpXy0A0?3GNgY@8s7tX-|wcqIr( zLI#?D2;(HAy?1ILIWZt>*Fq4%VG>z&dVFR$4Y;NUXs45VruR-f z&Yd%<<3n4L_O!-_c8nu-@8|n_-j!w3XIFopec$)_^ZWnrS(14dDv!EbmNbt8ZR_9^ zS79Hq2+wTxk6A&RKk==pG?v(076bshJ}Bo>OSQRD4ET5ci)4$!$aA?n-TK%PIr`B4 zNHXzgNBlFp?ixdiNTENMvN@#da6S9Ncb`Pw^a>FN0Ek&;zh!d%3i~no`-;Z;a0$VQ z`mP2OQOUFl0+br_gUe49)kp!vKcM*j8z)%W6gJs}yPi2T{R<|j+ynTR8MZ(;pj&2m+^&{`~!<$Ul@3&LjpPUZyf=~_8xHhJ(k@! zi&H;CzOGsSc0=E4{I{{Mh_YX*$^P4j{F?Et9+2?aX~MDgCo)&g*;nh}8TJnP_?WcU z#}%PR0G{U|T>sn~dV~FXCz^U7z&|FB7-aqr_D*j!1e5<={NYv;ldRvCZwSp#w&j?5x`y~Fv{-1&05WL9nx|koMMssla&r@FQ zs1pC?i?9I9lOe`W^i3l1C|@o>=_>e=xBm50ZI~M}`1^TP=5sTqc zgsJSWRpzmbB77eDS1b}?BLpe9eqc-*h`76%E?9&!wgQ3vFZsb%VV}F+^9X;SWdr-; znke$ixY_6J{$`yI?DIUopvwy)p3r}ukLLsR20&$gbPGCdgJu4sTk@}Mu>3<>KLX^A zkbZI9BO%sX_DL`O%UIh#M%t2@EA<2P9}7G%`2hte0X{1L(gIKq!+br{@9H`HN2Z_q z=(Al1BL=_V5b@Oh)`3jg(SLk2tzIS(+lK}GA=JxMLiQ)G`)wCoJ2CNlUc>W-=?x)2 zs+oOid4Gv+q@Q{FH#EH-;;`BYs4dV4SR}t^*ng0o36wU;t;0lF4^c(b)O}ELcZ;@*dsco=Kt&y)lwv78(nSi|-ttfBL&8 zv2P4I5NMqS4z5FA4Lpoc!`{8Kk_-TkbX+{d@W*&dV{Cze#N%uTyC%?b?3X{-wF@}^ zA#MZ!K#ZlzNoSbG4mlG6{;UyOi=YpF*u&AGt6+-u*XSS5a8HoF+cB;2!vt;qSC5}) z`^>(kfmk;{f1E+SwHNUNUO@|Ag-j!VLO+trAwR)ELEUk+D!}nG!9x20V!Qc1(Hepb)FNy_!A{eYXWW zk>CF&{_XCZ`Pcil4PhR>gY_$w=DJ`J+C}l3Du{>y)=9Xmk_6*(qW|ZNf3rRoKh_Z^ zKuq?PVjvtG|1Od9%7-uo7Wa+f6I)ncgvZfQgqV?M<}Ms%ct5uOLxI1K zUEmX}2e-vEA|O_NoU*zmK6f|K-Y{VCUmiI=zPOkQUnlu4`!mmv|P!6i2vg}-urpbnZ2vA57;@_1OjVhLwQ zvH1M+sz>DHPbFVLr&NF=;D3I+OB=%eK|DLU?w9Z+3U2nM%=b)8l^E94PooyUApg1C z-pB!scrJVA`-~sj3<&G)0Jzcrc|h3i&iy0ncBa?!%0Q*P&1Ghe(%F8yWeQ*1sA}5~GpGQXz0k@GO+3Wss-7O}_-R z-n}h>flf-~d692P=(cLg7U5IA@PD0lpu z(M!ccNv|^8#sZ^{zZWqq^;iG`w$jCQ-r1&75-v~g;Aj=hy6^YMWe47#>u+PO=<==%u-y9#mZ(`zepL;kN zA%7B`KmX+T@l$_<64x5t#Sy2SzYVyVgmxaoJgM{l!e~Je78v!|43q@X ztOhDK@Jx+-^WoF;a~?0dxbl(G?` zccuPDmW~;Ji4%T5ujRHBcMl?KaO*U6!!9bke{y1 z2wWhk6y6 zd&@xt5WzR#*Ha;e(Y^7HKSF+h47mHp?D^%!Li75%uBS#(U?7dO%KkH7i3bMK`1uTy zo=zu1JTWSS0^oUP{bE33nV;|{jR@1$w{3J33a)s2@U4;W`^}eo^Oed8gJ%F#5oQol z(O079NPt90XPH$IcL&y|^}f3ICVmt5#zYP)WBw@$)q&K-ZA3DXD^XK!^3VV4q?BmxvN_ zQE-qvo4n*RhMx8YPJH~m{(HI2XKM|M--7&(cV{P2 z)j)}%kobx?g1vp@SMQtq_kR=eQH>8F&s@hiR`lO`l!tc2i64)5KEgw>AJ5Ibi-BSF zlTY$v?p?)$7b>d&auzy*rvcbSzmXA6`UtQb-?+Y-+W4v6PC$|Vop@{fCz1BIGk#sL z&h637cHDHY!LRK5&^=NZ>^naYud2!9EuX$|Vxj{Cp+8*jJnIjh^@q+1KH}+Ih162s zE}_k1w8l0snL?Bo!dGCY8(q-&5ZvwM>ky5qfz)`X>8REQ9|M zz(D@pa2WLg{3nDLFTuBw&&)v!3%U~rElrq*^Pv&i@p|Hdi;o@u(&X5fpUv&Gsdq$wo zN8kY7{{4)vG5&tvyXDdMm-(ZV6BDqfwY;nhO$%g==V5<^zU`QpH+4=Js@c>Kh| z!m(rDp`ZMU#Ks*r-!%r5y8e~=V>VmO4#k@IAN72HrewPP?6a5(s`xJwk0(H0v4`?qpqIo^SjX)sq2l)@~@pqumJc=UxtHVDMT{9iM zZ8ZOhYo?HxKoKeldCCcbtWZL^g>% zfZzv!0WXl*I~;9$w79SMC=YL!zWSXPUieGa=PzG>;e})1m!O=&!JHlC^f&$r+AKZr zXOZPlCfOEQ9g}{i?a2n8nWZ1HM}Z-oPR9JYrx-s|7W^&5<8Q$qC4MS=xEbHf-pao!(LP%(HEg5+zfkg5AtQTIK(%kL)lOFs6P^+xCmCV$aNOLRLG{oX(D(x zO-X!V-?CP_A^y`FDTd3of*+cLYs^>EJE?Crzl0Lld6AyJtsnZszzf=lw-V&9BOgOw zbLB!TS(r?xc&VTKcGBm~9*O)60}SzWd`A}FHb1|xRK!PoG1YP21I=;&%YMff`NR0n zYZno{FpY!*|2g`h1$b{vUUNYClaWZ>gbRWszvC8@+Y`GUsm2nwv_H)J;6DD@F1Tp< zJ(7@^pzlLh@DhL^if?2AA%8-m4D{Lci-#@C=k!Z57lG9HkdGXRLcvgeP(6FeclLu1 zb-ixEhwQt)Isb@@UK0FWwZCSS5v7v$4m}V9RR9~vY4H}gR!Fck{#(wjvga#wCcnKn zZ2fuE*OSTP^WQz-&5hz;fd6cqxa(er9g@H6*+$lQyp{?58wFzjZ}jmW zD}JLc_Yd|x`KSDi?XBgl3O5eor^p){|LYL-b@Y~hIuQ$927a zf&MYQ4rK^p-UVH~`Y5~|EUjlA{-e!4@CX-Dd zg){`v>#j-tLjC~$h!6_5wr@PhEn4BvHQnEMsFSY?xf1Z-giw=zF?2^XJCZ>@9Wu!S-?5i&AywH`;Y!J58it#{B!;0;oY&=kyu|}r{ZfOAKZB{ ze*Vs4bNqpQ1OY_v;<9{iO#U4AclHx1Xb+ceFE;yUNx^>OAEo8bdP ze$K_eHbSI)O;e%_bz?^Tn^A0dyZfw}c-S0f_bR3sJy3O8`WE`@LK~Tc0Dsx%=HyDxmcH zJPu+k5iSmXhQdH6|AM*DT>KEgGrl8%i*BQzubBNtvV-@-Q$NJchWsG$+r3F(fx|lD z_ECluj_4T>-bRghLJ1?`rvv+jea`sHy7`aSUg>wOkw0X{^E;&Cj9UH z%qM$$dpBn{m-ciswx)h72oqzI^{?lKT|$p?1pM%b5WTG5Vs{C|1F6r9r|wT%a2b2# zW1oWjB-#j3RrLMvt;hqE7s$S9yZ>r@%j?{q_)69;uLO^Y)t>iSbV$joub#}ly6_d` zWsJ)GqONLH)>lzAkQb4d8q33f$#1zUZuTulTbDBJ80Y$@*X<`++$Sp1J45`9w6Tl^s)Bg|Omg#ds(wsIGd;#fH+9}s>+ z{&mMS4=ccwoodFH!s6HnjR%9oz%C3hQZPinnyp#?ZYDvJpISEeSx?b7xWDj+ z90j}#R>1yTZp$tAGjyR2Q{)&j#RtN(l3dNZYVlDPA7G^5WVU4Tqtl;wzS&<)d=UTV z7v;|bkdZXx1KHgGtw!$H2k_{Nf&G9%&k&%{|M|})(Z4$pjD!3OKbd-3{;kB=IInvq z75-b~c7b-8sk{1x2LIL0FLxhYyZ#`6;0>P2<<30e&0t`f-}PtU$GZ5|Vw$>;93&=4 z_aNSY9^@hN}^VjY8khZ9e{%EZ?z6CaWPcYaRaGHdzYNPwc>?MdbL2KHe#2$KW*3wgo1&P#v*zYzU{t}(Ql>90<{g+=Oxf7Hph zb;lm#(w`82T>Qwc>&4%^A?kt+;bzZd(g-rff0pfI(vQJlU`=f=flATXw!XgWqcf;K z8@6IU!G44GAB2D*AE1_{3gc)nxIB~Bv44^yf~M=)ms}8E>g|U<3O(~>uMxiG74oa$ zpUOYbJFx%PSOBw-S4O`i|95LNoo8m?pwq9<`wBgh1iv)*5&AXh-Gp_G;pOT?ePcfs zmJ~sYku>(=3+RXH@94jeC?IKB9rV|sP>tiHDYgA{eOBUT1J z56U3P&)!5`O20X8@+04opOH`UL&Tr<^?hda&H?$CzIPt;aq9Sdbp7w+PeCZhfSuTM zh~Kc^vb>Om%k(+5enV=yBen6GhtnO{A)x=^`%2i|U_-K@?iLfTIHTq-cBz-czrX{d)HJroUx= z9nWo3iMxlNah*Qhel|4WMurKUyP3omw<0n>sCA+B;Uz9C;Jw{KlSM@ zom^a;>q6<9S-*h<)op!4F{a7>HA0yeU;Nrf553%z$pU|DFkeg(NC3`iY%pI6(V<<0 z|AZb>^(wFtmu!fSHo(El^=08tRzGXxj!G3f4(qu{@vLn2FT7%7q22h=5l8;DXR@D( zKN*iR{R_rD-O;&ghwPhR5c^ZkHztnvH%6YWjy&4J`how;>nHj6%Ig_EnpgME2`=tt zbo7HwJb=54fATB#oq=7S3iLu-PJ#M$Sb zs5$x(p+rX_zV$Ho_tID%WSvMH`*&ly9sy=+`%cOyUe@m~iOH@Gz;w7N1vuP)i^`jqzcz=T7Z^z@Z@w z$j96@E&8HPKICcrif7L%d!fYdOkebV)hdi1mft71!QaO)o%|KVmy&|<7+eVZ8su$$ z{`ZW&^pk&}?6>Uz9u7cmpJtpv`iBAFMeUDfNB~ICoKz+*z=IAU-$jMRyfJXdK81Xz zkMKr5IqxC%S0k&oq}tc6Cqs<*5`^Gf`Ah}-!h-xCg1ckW^DINhm5`M5! zilT^v-wTQinwwuZecHuuDL$*{V_%O2`5jAiLOx}{(EVBEmLm3dt%^^41JAdlQ~0mj zpB97ylE5G=8RP$F*;fL{YjY24m4N)PkV8Q8weB)$lk-Wq@TQ zz61FI^vz~{h}wDWD9cjFwo|`GFKU!M;ME$5Ztu0DuRZ@7MP81YeXT-b4K>Pvk`VE# z($87LB?RcH6HfmYe~;$3jkx%6ViWE-d2;c1J5&e$z0Ci&S^a?sra?8!{)v$Pb5;EL zvVY$Yw2u1*U?xS^zGpXs|5|!yeKjdld+(cY!dzuvtQqrn?xC9D4>*L52SB6`=_3FQ z$iu=Po(lsOA_#n=en1)h2=Iz50m4jBas=xmhzP#?0{yy!kv_W(i)i-2>mK5l#112W zHb#c7Ka?0Tlfr*Ve=BS@lv60~s!{^Ig$@IYQk-hgKl zn}}j30p*5)DOQFRG}9M9YqAe?WQbj<#zsc_2ynOc$GI60P%UF@b&%f{&*my#jl3El zOmA;-WW-Bu9od-qa?jT53(ODr!nyl4ufHMzv{8HZ35TEN!dvGhGst(qw?e0t>LA@C5m-t6S*I~zl_Cr|Go4B3^+kM!XJz`_{$-ps)Rz2ae-eGXIQ(c#^%3Hac*U{#AD)whzU1ew-}yTJTb}z!Y2P89p3Ht#C@I&H z`_2#6Q}JWCUunpPtOKkQ4Td^CPuu=^hd1k#6ef0J*ogrC@M$^*x`bCq?>#O%w}@|hL(ZI!P}eEQyd zCH)}(;2*8eFa2ACuV;WS7hluCz7xZmz1`>+bc-0F1*7l8CqPmwvChss>%;stI~$~a zV4p1KJK}vK(X{%>FW{e7jL*;bg)vfd4tHF$0RxGi-&py40$R4@c9UMhSFU`!2h9j2 z_V4fc)MuakNbw_Hx}}Sf5oO0>;?Rf4K(w0p3OLNGllZJ%J-U831+a|2ou_yt5$Zor zCL7{!06y%eig}qZh}>4jSNEBG|9e{mK>vV$a&vZcTQa%rF_JvC6nWlT;}dUBPQ0Bs z_SQ}C>lOJ!y|QmE;}<5xyyCAqzH%+$mxpk0OGET(|J3`dz8`O+f~iX)qJJCx9bZ{@ zcwGzu%KCpf^7r|R8_!4HOPhV6Fnpa&j|6e<|Jp=*YO}>(D*uQ@ZHC`N1ptT|;+(a& zL{hxy$PJyX(RJ4()7hS!>UX~yIWb>-x-I|5`TR@weg}+7I~W6vg#Tg;3o_ArLH%;8 zAB&7#xh=?F1wU}WMLbu5frAFCkucVK*)I->TI9)$CB|N2?6+#%-toVn`nSOk24c+X zgkPi2h}j}RWV7y@;KPTw8-*8*hrAq4#0#I=zu$`J0bj)$u?N|{T;KR<4AkMl1X`~r9`|Ly*d_2WNHM_LEuA%|Gfu#ZLy z@{oIQ;wj-zYC}(1(glBtpH<29ds^Jr@{^&tH^vCk4#9y4#PVuWC;pZS5TIB#`J1zf zZz$yUU_G;UR{432d4^Yq$7BfvW_5Dd-gBywUS-W-2N78YZuR`zFL=Z^3xC}bxCIdY zcAi~c0_#V-QhG4*3ZgW7TMr+Yokc%=1}z7wK7)p`rVAQHqo4Rsq?s8L=%g=pOs`rU zP3-!7N(!*~&;I)>^UTjj0G^_LjCa|8f_`0Ylr6*_6atBWPm6zd@$t$(>|$(QLyw{f zex(*cHVce|xyZg8Cw#9~uOTBW(69Q>oF+69RL8dXmR}nhL2vz!(VwRI=H$uaCzO9F z&Mx+D>WV=K5>U`G8RP>6u2_B#B8dE};*9oY2TeXf{Jm3yb=z+U^hSyH1}nt=5TDKA z!hqHAt@jqIbTbi-?<+p<@Nd=L-sCQ&hmOEN&Hn)cg8V{%yI%f@I2jyq`6pHj{tjar zWHUL$3VolBAt5I94w6=XP*Up(`O)|zt0x%H7y%vCcR{+)-xnDS;3E_6<{9EY?qGZz zo1)Vto?U$YbdB{j=@tPO5Zk{W`Ga)AQfcD$^61Fel;(4}pZYI*ywyKo@eH3NW?$7` z6n`!Z5C19rs^?G1gn>Un^aJs;5XA4EkH_^!5|VyplwDfDcHi`Fj}JcH>-9Qno|C5IoHSNEML_ zz>9^}9CDYN|F3Md=Svfh{lxM+EWUYMC8UG+yyg4v{u{f$7=+V;co_GW{c(ARrQeYH zu=6u_-^Fj#bC1XW`cz3W;xA(`N&Isw^LIBL@Gw0sH&~0~KNx@UUT-exZ@>@hnG3R@ zKCa_WfMW*{pVH6NPb_?SNpN8NBdPcSix2JWcl~iC(D02|Ubcq-Bow?K`!#^rz zuJfxVK&ZY4@mDZt;;$?}`%HQNKkvW$-FGI-w~tQT4|}Rc%=G{RuI9*hi2tkrYdm%= z^Fry{njc`VAvXP!&^JjhOZurFTn_It0Izzi5A5M0{t2158@4{Ke#9V(F7Zf1SHKqq z`auuNy(q+$gOv6>Dic=cAvzErd~*d%@d2%_Jn7NkH>m$3iy@R>jn_3cURQk zGWsSGUSPP$7bG|0s`yDvKca8SKV3yJ*cZaM@}Sjka|$0&J!KRNuJ_l>Nh9(CsX{x_0r`}(%{{$|GSYw-3i zKI`UhD-h(Lgx_%WS3w!j&*&cmrT87@Ap;Pj%al)}W#B(7igZ)oFWv{KPeVUZPhjw8 zTJ%AgQuvJMyZwYeB3VL%f}aiGNtQ_}aK}54UPXT;{4|z-YJV&_#@7u{a><;;J`fJC z){R{J1Z&%R*sJ3ILcl6K9Yb=vl|JlW&;yoNGM*Y4_g?r6NhbQ{%Ocm0eD4oO<2&x= z`HX=$94qW_qO~~=JyW~S)KKvDFm9_)$O0B~edu@C$9VaLz8#s(Hw=Htt2KNmu-6#9 zgq8cOh725$y2=t1Jmq`3zlpC2*K4C6daKcPEcRf?-9L~IQSZI7?l1ch0lx7~k6g!h z=$GT~Xi@KnEPgi8L3~t4^4deF3*-kaD7c4L13}_DA#5fJ|3%(@36UN@~Pv|GL%}MK$-o^gt`-!J&;G^oJeg^+5FlO=ZkR|AnQxW;u5e=6z@fNw! z6`w?Xj8ZPDO$_SGcuN1P^0j|j_Lt_mHh+@;=>qU4$F)VsXZ3|NTZ{EtOC-2qpH{>9 zj0t+3XK_K7XS;uK)YZ?qY(G@}Qq`w%g#jc-NPfGrAAEcI>7V=&O2Bi^z4GIE;D^;$ zczdBAk2@F!h}W8Zj{rcSnBj@+d$Y4LpbT#J?;4qLpMjKRReh(5aqb&o5d58?dCY{|_@xKNtE#!%6=bvi(N} z@_?MU)t4#~e~*8{qyxzxry-!$PC~D+zjXCf6n)%`PuHHxqBI>B`|0;^EOL0nAgRH9 zpZcx6*OGsde0w4}K>_IrOkC8jwFzbsBHjG(FQ(7Ov2~F$+_QI<{pa5F#n?U^P}={$ z6Z`sGwhvL&E9Jn93K5nm48WDU*uRDEojiFi^-hZLoRh=izoVap0dt7RZwG2j3`eiHx*k^WaIuJm8vBm?1C;CFLx~LbouV1=$W0`@PX3w9##rlcW+Q&w zjqyyj?0J73`*Gs!E%WhHmof~H+ah2Vi>6*U4V3$b!@jR`uOngbC*%C{eSO5wNxu^8 zftQluXZaZl$#m#i75PsRNV7E0GpG<7%mvBkH;&-t6{TdRChVSgJ(HQpId+2i4=U>Xz$Hru$ zn*V`2f06U)cHKw%HMhWjrE1iTLS8?Ng!14JD~M|f#w>BSp9j7>OuT) zA=3HV06470#Sdem|1~4SzZ4;B?}oCJ5PtEC*h_G4PDsQB?4@6*K!Dt%%jXY~d;sk> z1`UpKzQ*4BC?0(0A(anifvFF2sdOp(_8o6n{yX|j5P#|DkHgoM=WisY*9&%g4u2w< zD-!=+58~h7yxrp8y+;WweKgvezcJoP{UmKq1LLR!P~o44`XC23;hpIa{zD}DOEobF zgRw)Iw4!5>=>$8!%RKlvfxGM`%f(5+7)a_yAv;pzO41#Ug|>=WDr zK|uIHg4)K!HDA~M^n12H^Nq-*r``VW&qp`Jcic?H_~t6D#ClP3(PY88M0U% z-aqn1UL$)jpUc=nL*L3~!GG!_;IG_zkQLq?j<7#+4!~fV@iAr}-re)%o?LEsC@kL) z(5?5vg8XaC{3(inCwa3vJY40QewaMp8rf>;=}8X?`eQv?23Nv|%a17J%zh&YJ1Y9`_`$CwCPXia zzB&f#_=ofZmg6#m@~GdGZ1KLSy-BFP0O$*9qF{-?1K-Nen2yD!W9SEK(f^{+`ZKS! z{k-y}%4_rU52l^@WNe%OPzv-9V>UAUzP$eum-Y76-@R+2Omr*wlYi?`)(6xJ>a%U@ zrM?5^p(6y~pa3dSnCGpH#;PO3`+sX>|1hW6xc-@mi5b@~tYT9j!y->br*?Zrf}H$I zc}9gE6MI~)#DTAREm-0r^!qgYeL1=_f9JiP7oKZ)^U=Rv{7=t3JNL}u3!-1~wDe^?Efymwl~Z8x!R>D#g8Ww{d!_StcCC~z88>hYoG<MHZ(fZ zZ(0tILPwX+=Oh1&cvtqw+F3w{Ft+=^WMmdczu8(0*yoUO&Vd2k1pBtdPm!QAW$U9S z8G99frMe23WA0=5hr8d61l+YeIq}$!H9uOxJadjM^5pTwOHYNc-|xR?N8$(-rgl!;C3(0T=;sTjG;uC#_WS9`s%Y|4 z_o}dnp5H+2nTAYA%mKd;OL~Ty@%x`;{UF@yfTB6{Z{kbb{7gf$`AM)=@~6IL;op+~ z50iUn2B!4`x_@fm%_#i5Jo&+5Sn^dNyLl*^@w25;xs&^QL41zy=!f8YMg8*2mk3F`-e&z|7H7GUtabV<|qN}GW-~SpvYZ1x7FFlM0h2{@DhKQ{$A+Y ze#`d0?W3dMABn6+P?>E!_h-z1hWuuuu-T6GhxB}Qlr0G2Q@jGh49mE|N-2P737}XG zkq1iDg?i&~C+I(~5uOE9fPa-Q=x67o=qgGF_Fa^Rf1cYhyr%eD&~2?*P%3V#{jd499-Y_l&L0%kd1qqQx5Kk$HA_=ga| zaJZrTUgY0mG=9^VoCmTG6zAj5m%sh~Q2^v#)lcAT)Ux_fDWt+c#)!^Rgck3=pGRIs zE*+=-2o5MU=7)p@_~Kw@-ON8`_;KUd_`lvCPt0K8-*GP@F3t1*-`uY!bCbwWrNv*N zKN8=s(gu%W!0q~~)(7|D`+U6>;E%FDcvYk6+?}0y?CVPyug@bJU5s2Z`gN85sB#O_ zENR05`m+4aFOp!;H>r#C>gDyZ_>m#L2mLwHD~XWM(LNCB|H`glA*I04S52Z}d|P{Z zKH}>e_wdhetO1_VKBvcqR>NJD>jZ;h^QLP2;?}1-yW)HigPm6XtGWnLaC!;|i(AM;e^7i8^d0sy zzfhx>mdOB*dH|6D_5ta~PVWlwOSJ18{MS=j3r)c_$d6ps$j~6!M~|}qU{{s6)+8yQ zre81ym*A++5WkLHA+E~fDBs;$EJwY=v!w%z)MFTcI~Z?JfXAI;2WAyOI^zrz26>jx z7kFgQ3O;|c0L`|<`KqBXA3**wEL6V$`+{Kgg4qvQR^GUeb7r3(JZ(E1++>MOet2U4 zt)rf)P_1VT|3_=nBD4*@=?^F_PP+Wj5- zguk$I;;(i-nE0z#XB&)&@m=|}*uB}qt_QWo=$p-{>ZkSx>LCL(l5dr%Ax}guB0zci z2B_8e9|RTH-&Bs|l8Ya-etqWpJ-2pRd{oU+$mUL*m3V1H*tMENd>WPKF2_Lk_vDb zZFl}lcBK)C5MnxprGR#Ykg7R z%?0E?U;IAwo_@}kQF?j@%cS#h>tuIWjFa$F=f@YZAHnD>zSOOY?V$|?IB8M8*mMT_ z5qM`BE-PpC&!`{QLiyw70rae|?-tfDT=kE+|JFDs*g)knMcH?y9Y^Y`B6hwP@vklP zw@@E>qvD6?gLhmWpJUrhjis~(@W?iT`$f(3LSk=7Y-u4H{)IsM@)TxYW0Wm|4(Z>d zXbOKmwmz2V zc|6wp$=gO^*k>D|y}j(XY6i+*Y<5{5StSAnKf9v+8Y0H}j-4O+h3lpe3b$VK)rhTM z^t{4*22Puz07NrTv;G^9D!yOFou-js0Ja{;#){)2ev9#=L6TjxfPT087h?Mg<dY zXO=(9dNo2LBlGM9Bpm(>@nq|&WA_=N0B2;LVR>o0WX~XMc}0F~UrF*hd!~EQEPsZX zLEorUC<4QJbMyoQM2wSv75fQBHCV7BG}X90k7zWvU;z0nTVA6Asic>QzL39IYn*!b z)Twvp-Yw_QXPtg2`9%};kj%>UGTH%BMnmTZF%!2wz?twDsB-JW8p%I5xHZT0Z53Lm zcP02+kAg9n^ZszI1i}a(wP>xAm^ubiaci>GTFbtz3>K zGc#N&e_mDk_62`qI{*KqqW&ZFy}Wm{GIkdMEcfm~K)}3=V)WCNsL)vUsut*{8pj{o z`5P#g5pZ8`oxdUWWUl1^P00_dS?N*-VvL_0CH(f1LzKU*)kQ!B|1Kawh(39(s(&2D zI-AMJKWqaoR*O}uuZ(^@K3cr5TxLG^74h%AG0|)&X@8;hmj+Uewk0~crldbv`Lwqf z@e3~~p2Ua;Bh=X(YUks6I{OR^Nj^a6pfrRtPe5jB5X1JC^R6FAMzl#_K~1ga{8$d4 z6a9cIW5Yf0C-?rzUEinQ)&JS_Zv>wGUa>@eRm1NF-%Z9AoxYQb4Mh^<$s_yI0qnD09Pz=KjSZ&aOosW;Cxuj z{}8b0>g#)FeHyXr7CbHgI)uf?sa^_8~TR@7~>t|6+bu z;=d5++NotJ7}L5R{|EV*C2$l49{|RlJy`LEhaG%iAA|lR+W-@m8L`h17$+b@-x8eg z#+UFZ?yWw&wd>$D2UcHmfH)AgSk$33Gd?aebt`*IZ^f_InPJ-!7-af&0Dq?;gVVx5FYkcj7_a-rRa;Vu^ceUalWD*_z=NzYdWITv9$BV%&0^6Z5LMG(xn z^EudHVh@xaFnMIP7xHG|?PfVBI{5@3gZPsIY1Vxn#-sT{|5t-Pg$p(YR4}whI_#Ht1r9|z&(<2H+bw=ZJ4B{dQ5yk%)oN$} zc)pJYWS;peov^1TFZ)57{)UHeJ2`o-C`X*|mkAJ>gq-d4FD88F49oGJ@i6`Wr zRkQdK2nhcdj4pA$a#+hZC6Y8?8X z&=2`DE2F0B0}1`)`BVAMc>d3UEyRN=w?Q7GfF<(tNruIgRDbu&v&>obmD1rtdwjbd z26|Ip3G-X$+$DauHR1k*sbM6r^^yMEK!a#R7cL4uQLWPy0ArZ^q3a1C!?H-jkwI+C&RX3O*O`Es^4J6DmQq*0qa$76+X`XTm-ch{6D=rCu_=jSP2YU`eMF#oH_b=v2?B6N?pm|1K zwkrB-odW2{*ZzS~7eSEX1EcBQFDKh!K!`GS{>n@#*V+ERAU!p!uh0HO!Y$Klpx$k% zO}^$&d9L(((TnphotP(H=qmk<0m^xA-;e@4sE4LVfep7^n8&-$LL8gt7b|i|=AlCS zHDAMq=fzV>osTEqKK?A{)0RBIugc4XKvp9j;70+i?Ba3CzpQ_;gn#C?J2?N42=dS4 z{$xFVo;^7^pZYc9@TpRXeW*%?-KImr0eCxqUqG?6`sMgnzK#9`V20bHn-qjiembqe zA_mK6^q26=&aOUkfZ7Cqm^bB%$(82}e=GpX3(xRc`*r03i@baO5HA4RhyLIwfB@)6 ziug?~T5$v9Tk12?h!2Zf`cczAp0CU^9_S5dZ~Xl_onIKz=y(Pooa@8^`vlvs`pP4; z&ru!-`7P)#6ToKnLFH{d25pgaZ}NxSclELPXaB8S2(o`n6Ta3zF`@dfaW8Tvl3xGM z-}~-&|J!S)=H})++@9SbMVEe6^cy(tr@l#3!DD=k2>#;ydtjs&nG=C#j}VdUd;}^8 zV7!FAsD6s{3;CD4h7K^)`Fke+tF#IEYuw9Y<;Ngv%jf&D!65Fy_6K`=dvE^N`ti<0 zx91BFBHyL5z8CF2(DlI3NyR@m7DvrKjah6=v`-EAtu+|mQ1IpDQtKmZlzS8ZIXg@B zJZpf5BWx74GA+a2v0r^>kpf-v#yo8^ej6Hh0odFbFzw+@u^GyK$ zqWRES;$v#B;`cNk!pW@at027|iN&tFwig+d#@?Iy)^JMP-5%l5<<0|P&h7z{L#!aX z>lfG|Ow<~$>Vt*Nxs$N)eBXbqGG`{tpMGEG=ZSn4GFjZ)1q<(Ed7!}A;(V9F`)XJ5 zN1Y!f^NFb!5+sSAOsM|AjVeFGUXl)yH6wI+F8b!c8RRoE^Df7y4Kp5-F5D0JH|kNY z%-OYQQ8d*rdyUF079etw$v}P-+f7s`)f)!x7^a`(Y=ShM@ep8l(N#!T){smjojDne z3OroT=5m4%;hm$S;jrnyZxbOqF;ODJW3A?2xiit1B1fg5{95s!$1rYEq-u!(PY>3d z1Onrm9_AbMlQEZM6U7;bGzd6VGyEibeB(8bfM*?_cJd|6t@!iNpOk+x&U}H7JxLLdBDtalYSXS&ff4foQz%9^i>pp2q-;`|JB$t zhy-nnko%YK#mw}{Y>(o*<8?&i{weOC8yVto1Q)+(@NtFxwzohl5b)7 zX@d*{;mBgQ=|_QBAwfTo6aXu_}wx;#}mlk&z?>FVBX! zKk>&m@9Mv6Ot;^_`3R6--VJu+Yfpx`|N75Q?2mU`7vG-mDHY+5;dd&NC%xQD4U>Ne zuVZN+V+SeF84j~1V&97m`>yjZu%CnrNFRBsD-3u1mH2|*LVna)jeWWtF2EoC>YTb8(Jdp-otu9O{6sWFaWUmkAV_Lu(LeE&JOFc- z7|(9+$YuXO`Dg#c>y-w|DKFq3%$P}K?-LNm)5LE9T=jg}P9S3h;J5Rye$~RofFJTj zj^uLpEOckjrBr{Mu@w$*bjGIN))WS??`3nHxhE)6=bz1=ckv5_o^hOWt^g$om7A_lNp&y+0yeQi>1m zacdpO=WMVq7NG|GM0Kzk@_*1+pLX=5<_FGNe@FiqvcE-m(l6tYIT+2q2u+PEen$zO z&c7??0TO`kpPo7)tFeSHY%Oa)flLzt-rq(%q9yTxiaxR>>A(U8Fo-^I{9xo=5b#}# zpQD?xr9Ip?lE-VNUda1EsIn@D81=^ZC?~g_{}~QH#+#C{{4n}!YblYv$o?<^2nTH_ zKwtgK{?AXw!u`dfT+{lP{h~wh32jNg=&@>YtZ^G*p!}OEzvSvKsbBO*;cc|vW!%#5 z!pP>g0=&_5c+i9X=ghIypvcT2#ra{n4KMKlnkw zqBMA|kRC>}OXZ)Ln|qE)z(24g;2`8XKl#A&@N9s(gjs_lKyJ1a;(DXYOJ1!UmiDt~A4<;wbSsviaXvmheRr-TKzKbPyzDgL@qi{JgZiHHAcY)t%3 zLs#{?rhP~WzS2u%1d@G-hl+I}e(U+JzCIgh^=(Z4WpT8&u2nUD8sKLQ0IBi-JZlqe z!oMl@hZ&SGF46S-U~{yD&VzaQw7LlWLNddDzG`n@N3!p>wrh#8TBGX=(fQY2e!2H$ z+8@HN8Ptq)H|oFftKu~XFrfC8YYpfHA20=i{xwm-CynX|<+<74`-O})3@f@STt$-t zJZb!x3zNTL2Y_9rU&Xw&CQ5Q-2?11lzwrk6E5E?t1MS>F_~-Py@5OU>ye|bVaNDpQ z%l;=rfN)cOFkh1TtY7s9o;|O)ZwE%e2kw0x9^w#z^^(i-@La^mf6eTJM^+Jnck_NG z&iTCnRsdS~pAsO?RrVL*#})Xm_;=#FTHHWbKkPaUbfm~!Ij8ts`a{k7D?Ni2UyNVn zJaAB;;KR~bS zt|D1H zXx!V+X`z6?5=77m<^zN30D0G;s{6fA+J=Y#{TFQ3!;ia@Bvoqr=B3_RI) zBDM&eXrP8>&u0TKBKcZ)M~(jh8&!2H8$$F=VnMUW$|3$+H4DLYhg1M$5AaObSU#S+ za+uqHtUr`Vw4rv2i)ONA=q~`K)01?3 zlI3@BDCTfBi7y}l6S&ihP~VHso;n_l9-sKTn*kGKZt_2x=Ob|C{M2rZ_eAhn;&uLk4WG07Z*czMS9(rlMhfZ;BaPN6905t#Q8$N z&*}lfuM~o%F${?oH)cz+Aqxw+zieN{Owu+;=ldWZ5}1X>w_O~D$C&{I*Hmt6x!l^t z`bd72eDVhaW(Bv|7Xa(Xs_rT9E9)ctJnwVw`PeETPVxD>TLvxu8Tv5)%&%hkN+bHK zzF*~f{wMUvv(tMdd`z=a9?1=|oO);=uiQP+&bXp!*=1~(f@q(2khb56X35V zro>nK0S{Jd9XQSR0RBwl1N>bA4C^yHH~;<9H8q_tVet(rfn>j|(fF6(y$5rvPTD8>ftf(k(K;*+@i0{%SZ1@=$nrz3YT4K0%P zAETxL-tAzPhWiTPmvEOYdOVjor7Bb`+nsfvC2jR z=qQ%=0igPX$-mIW3q)oaoyNY7)J!m*q2)A5FwCJZ3FctdHf7^Z&_-V~fe15DSwRwdTN1 zYx^$jpVa>*Hf`Z~J;2GQ(4Qk@Uyy%Mu>7FX?73_soBdVamUAbw*}v7b%d)Lj5V%_o zaD$AKa6o=%i}E{3up|FR`y=bsv^Uw;>xuqEDNZypLWRuO8ay2QIXvw9Td;v;UU(tR z?Zx@4u4tL`DPT93Ka~RnIbO==^QvDP_>WxvF#ai9eaUHBf8|f!>L?Eb6ok=G{#bzl z!5_`Oal4{p59B`A5RjE$Nhk4vIzK|6GyAGtk8r~ch`*1W_pEaDMt3&A-}K;OJ#;ZS+z1chFO_`reRyBJe|s zqNN#x80XQGZ5&uOyX~FqemD$2sew4n$IpVkN>2qh#b;fshqFG^$J$x`B^cp{ZY}xY za7`cxg7YQ#bNr#n9z6ah<*8l^>TfE1YIjfW%bf@yn~U&wO4GB?jrf4bAM&R1Px7}p z{|WjLm>r5C+u(&}{eYj)qtqR?6Ta?W%?KEl2G{T@u(=udY=4LVPaQBaKE~}f;+~^l z!C}q(i{=F?3+p;4!bDP5}Z$<;KMZa zwdTV68B$f)_-Nq4tKHe9Rs@K6xY{fsDA%xlkqEIp)&>vCKBf=wS-eky`~c}dyvM>BoPUaV zbb;zr7QSZoAFZB-ApuwVjaE;?aQZL20pgI!6e6y^ELln>SyG<fJTKeNa`98P<}P6n@) z6+gtPE5SCd^AU}I`AV=fF$U7Pr2MSV-k#nVdK~&i#gjhw?+GBY779siMnZ?hN{z<; z3HlKL@odZacoz(&U-j6q&m?aV0ag4Z{tcZ5n{WEhuHHX?usmm;z5aG@3i*Y8mtXkF zZ6hNw&flt&o?VXzA#CK+3?1H#RtPYgZdyfdhCUs;^G?! zpkfh`FKvB`LJn{n?FIkg0Q+B!I3EJ!9{Cc|u;5t<^@Za<9ER{H{T(rt(ul@RAz!$U z{L_3sj#qqX z4+pS(GLHf^c)$0|({C2u1i5~C{2e=gLnBx92K)wKJveR{_`V0=I6-K zqq_W%*%lB0ArI&u1c35F4RG}Xud+{5--O&+-hH3kUUBE!UbYWIZ=s!{p3Nrsw)(4z z9ufV7D;x2*Z_q#JzZr0tqrn^Chs=HWOp)g7Uwov>SJ0sSP2Qm2RCH+{^YTLmI&IQ)yj=;Ym;cfcULmr7YW72?3f@cV(YR<5@Jx+s$9K%^MVgCC5!bau@<(Ib*0F=44XmZ7S zQ9-seKSXq6kK!v~VC=;EZEfXp-_Arv`#;0h z2KGn!hh_JktvAO9*Ipk}{951jP5D1GTrJOk@7OWDgZYydje#heD|&%p>G-J+=FXft zKIa+vg-5`jumU1yEX1c%smWdIU))2Tr^XfivNtvRQ!nlbm$MnhE4XB7wVUiutu{wP z#Bjqjs!w?Ogp?;f=+*w>`P%94&GGP4eC|2qV;#;BdWe2F%DzDVCrT%q@uxh=$1#_` zMueRF8@2ha3k&gdjrhU^)z{|n9Twd-x&Q8IS?{O-FJ~mnzd2|#O-r}vhkUicA9X(g*du8;#S;dpbk9b7J=kl?3 z#m^|dE?@bMyZ@W;|3V^KEsk{)Ui=9Wz#-%VBqZ^Fge2$@w({lkE2zKc=kEA0pTG0@ zq3k=y=bw83T#dD?Zfill$B9&GA%0%`Pa>F!Vbo{J?rF0MsW|*tKPMjn0PZdLBz>Z6 zP|9d%@Yi#8`V=vC=w}vQqWH=Qt+2aZo_+TQCD^@Wa%W%J5FGwlJ=#1nN%FgL63I_i z01E|k}?>G0GBpbem0WId5nSSYFQ20`!+7rrRHuJl;meW@>zGKNrT;4Z1N@f?;mt(E5|M8` zom}QxsR+MEdNm8NjKt(W;#458G&>1Fh@s#+YYv-Vc^cwTgE0z!Nj|*h`cc>{_$#r? zwUX5bWz~lG+X(J3{*}xA$GN$PN`s1b3o~1%l_wzH{oyQ@$D*@y;orRt>rs{SWmQ0t z+fURp^_eqS4=69awJoP599Un0lW`_&t?4`!Adm=w9@4i^o`h1WD*i zGDWGy5Y%;fMmZsJn>IQfcbzU!l)l+*)}MmU$iy21*MM7 zz7gjZ^A{J$15m$&2J;|LpaZ)G*paO>fz-?!0$~=9TMvbXypXLT<8$*{9-sYN3!L42 z{h^RiD^XZP&f(!%<;SLyg$jEOcYv#sOlvdV+8vVrOicnRYe^kJN8h*l z86P%KEPC?a)jbN!J`WGXN`2bsUu**oTvizb1b?i6hp#H#s*l9{qlsHqZ<=b>&n7mA z(Z1>h{=H~yeddd?SRuCUlf9qlnDV0U2)1tPW@*ehK}-5@*U4)Q2L#T=!(%bR3>Pyp|zE6GHGLo7T4KT)eOLmgsb_>bsm{%h4g3hWcu=Z@;l{0jLTCK@NdD}SZ_ z%rgtZa=izL537vyvNG3V{h;xDG`m^^;uZMMq~Qm$mGu8wO##YtbF;HY`L)LVonX(* z=^mutdY_($n5$O`vIp?8dMqF7N9tyc)jbCgp0o8$Yp*ss>LLEQ1dS*v_?yQ5>SBs_ zQN61&#$SSeh3HOEzH1K{L4T&FC$l}zF;Ez}>1#wQ_a%STck0xsSNh%u{!tLP2QN@P z;(6h@&ePuP+=*H(^oH`y0ExqE%*sV}5VN@GpFVcs_=)%C=RRPH;4}59L9DJr8s-l0 z%VYeS4cs{z+u{-4==L8oiR^cp`r~|Yeh~Pp z{Ag%rwjulPkjcl6K(}-Q{RaKlNYUAUae1)Q<}CJF_QG z`77~<^}{`9{nF!^AK80u63o=s`aTW;(e>!BNsq#*l1z9vywTB+>L0>i5}w6JBOflW zFK8_OLvXZ}kZ$%T7LS8rm+@Em0mGZ)UaUEG0E>u6cO-bgm< znRqLaJ~lp%MOyZJfWM8Sk4Gyh+#6i4p)JlfW@kx6lKdVHuj~BnKsQchOCJ8A;zbH< z2zJZajPjQ_HdF?VL3h4JT~tl0PYQMt{TjY?Pk&q_6ppb@ux-R`&{q@wMmj@Y>!6Is zyn+9Px2B<-Qn;R>pL+%V)Vnw|09O~ zSYB9rWrQ0Im3<+oA1V8q_;*nq6sMK>?vU^=BHKSN7^UGSJE!qo4B$JBcPtG7bN(Y> zv@+Ly76Mib{71_FouLB##Dvbr(44tHV^Bj@xXS({@kVj204Hq*{EG7QCV7j3UkkNh zZI}=AjmjLRorwg1AAa4p!5Ih!@vTww;J*fCF;s1sBc}nPx z+5Cw=m=5g@4_crAYG@O`eC*HPR(;CdNGHqZYf&FWE3?py5CJ}h=$Cxrq`b@c5$H#k z;~M}(V9@QaZsPWr^O*`PUuY=QO(@lKE?TC1Q|L5F7uz>Te*$;Wwd+u!4IycFWGEWr77hALEdJ6@y-Oa4fweg{=KpZ zf~}#rsfqu11@SoSvqpb`e|Zm!kZwXfS4;e4>kvKQy(+b(_^#7$oO;PsPvv?@vsu5) zil_9EnkDGZ%Zm3z&Dh&!qh%52FA{GQ>eDirv={0Q7Zf9vEUaFm`iQf{9uxYpxcGK5 zIeS3y@9_=-)X@FA4{$`3({Hmbzu~*&m%zTLZ;N!s@l>HOV_hMgB{Fw#{YDP(?%db{FDItSzRmUIkF<3d{cDt;pu_=14l2)l@PzogQj39*G(!RZ zsmy?F76>QI{!JY7^G(Q)MRhgy-%_hb zE{eXk+Uac)fG`izg6gk<|C5K3z|w!2KN(;zEKq*N!tkV@4Ew5|n}Gfoy`s)X;%t*7 zMo!VMXeFPA{YN_`|6u=wyZi7Z%%_$4xiI+9q#oNvV}K8{?I7hTL^RrfK6bEviGfc| z-o;FHeobSprMW)uT6}fd8)EDapb5esK)ayXSo?(jogpOkt9Ak17N%SvrPwBZ^TZfwtRkK>(}p5@t6JkzmBIF06;$N#7BaF z(dgOzKWzUG<9enMzbk#SaajTNpueeP9t_G3A@^*#Wy*v6FMyxcewPgw{J|}#|DoUd zF@kfzJe55ckP?4{eM;~X$35f31Nl=|6cFV89;eGHxqtsB;NbB0tNSVD4gal-;QmYc znIhwV<&}D|k@@Jwk9u~$A^+jl-%M=GRW~F*fA<9Ouf%WkVj1~WU*EgAPyTZj`mn9< zW~9Sg`nL7ma$EFc{W5P<88F0)hA?B)TTdJplC2!!0eFA!;icnZnE_)*TESS=pN z{lv90oNz#Leo663PO3Z4)7UlXmr+YTg#_qdz>l;O-jX1FANgMOnZ&y#&meCsvFMiD zAq@yWQ4GY`F{T82n&roWe@d_?4NdkftS9j_<5Q}i>~PEDb0gulM@Zf7>FGVvmdp*S z-Ar+VG$td2gSzKf5D39bH);U z$RmLW9!zWq=ACkc@vy=`0rWT)lbkF1L4GmdrQfLE1^9~bXbv^vXXG~$ee8Z110neZ z0y&0=@aDz`>Y(tz9F(Fp68)Hc#4Ci!l$Lct5W@VI$PO$z53HWg0!gqD2I`0uL0%w@_>I$#_1*M$&e*Go%N%FTs#Z0_4vP$ylKJBlKJ@k>YFDm|} z=yNVCX`HgJvThS&$JRk6?0`X@9}G=nqt#>paS^=yTH`?gY;+yn~n!J}zLIU}ne(B^x=%bU5jvZ@oen3O;0>S47*guv2V*ZI5H^Bbc z`FAzvpSW6n;~K7BzJc~101v+W0`t=h1ezMY;;$(!0SFiXltSPSXaNX_A#435pXmtm zYNV-?#WN_AJq?-hzOtk3-p9Yv@N6`6odnT+3zo!^DyB?5yl09?=yFt`mWh8LlSv zwC97-st;%RbKsaMDLhE=Uy*wFoSBbg|M(2? zKR5FV-HZd0@z#qoB$rLTLyq@52ZlXrYsROvHCgTN{eTSWU7+BVXIX=*?aK@C!q|%Z zbnIuPahz(DktltkSQY&Uw>^Ww=nYkUVS@x&+p+g;_eVzdb#nj695Zq8S94v8e~^ds z5$Jq;qt*w=b2|`UsB3*(f}$+aoPQSawD%!W2%G+AW*!K@ltBW1RG-EPz?{SlfP$1AsuJSyY%$ZeIwtrkB5pfvabQ8m8NQO-Y$bzQSf z5+eJzghIdfi2zBNQl{e*4*}q9JD43!fA4?@-Cd*Ec2{CbN&QFWGBY}0kymh)Rt z8A>^VQ&hZ1`xkTZJ)g`ET)(I2)#}+-E@f}EAOAmHZv!01dER;U33;itpZEFrKVREJ^t=4%z_8z=U;6E(m(RZX&e`GI*|XVbr!#9`qSdd@+)un0-+3pl73cSe^dLN z)5HhjAGkVxAt-a;Yc0)+pS1?bnfpBN-NVljpTZu;H-deG<(NJNX?C83t)9lvj2U~~HB4hkd` z^nAms=T}#G#Pdsv_vh0d0T_zF7#NPR|MrsHz;5rvnmP^tbK)5>29MY=BK`fc@4E_9 zVpa+csPh_8zIJ4KLbGq--{7m@#7nc-XUuM~m`4n;<9n6AmR%)-TS?rkFZwm$LHgEF zf3)oLjG6^{vvP&3n`if=&v;h6HS8mbf90GS{@7s zb}+xG)I-x?c0kA+9Xy{jL=F@L@gEM!HA5q_+e5`ifIko)(bkz%{c$ENne6MQdvM>* zQ|vE3R4Oje!KiOgO@ffGR{Ws-c(|Zy(*uhtB`=Qkbu;S5^Y$W0n(7Z>hLTjFF zMDgJMc^<(Lhb^^ddY|sCqvEN)A@#e~@n6%QnHN)&(NB^*_}p02CYN7EeC`tSuc13Z%L$8a<%Po4UNQxCxtqY6UI@3qfQ zex?GLOR;WAx)M5xqRldSp2N+r{tp#dN{sLa=3I{@9i4kqlq#Ro0`+=?x2Qf$e3|;% zBt}yoCfA97jBBEfnFETY&GWb5Cn+&|C5ENHM)AYcZ>RrOvjtB!WB(51{(GK6qUTid z7Dj;w0$#i61o?M~_dPIL%^{z+`tN(4ekA=@_&W$2N=60zI9|whtG)d;X6I()Kk@Qs z*eYkS#)=DE<$C!P>DMY6hS=e}9$t4xg+`C&`LPem5kf3{mI1QG5F`59&i(fm7u6y} zRYk>b5v}o91HNgLMA;{ZRvcfO#T;4MDE=*Vrv(sW|B+e9zPuVAiQ3n@LsO&ggX9m+ zE^1VAirl04C8%TY5h;&oDGhbAp2P12?ykYU(MZ^N9qe57C(kh&*haF#y@}#191KIz zzqK#6?Tvly%6E!BvEwwqJb>D#=W+8-PBsXiV|%Y=-)dV~9GlK+|Cx0m_j$;hhc57g zCBATqt8;zn$LwLfO)uzAj6o98@i{)tJiFw63XFiCLfgh)7db_I2;_ru)a~4RkSHvX zgR$vYWB$mW0>5$r*s6bO>u;;C{AlPl3-@D*Fp#lt;U7h5M^#(sIqaDpi;qgu)pVTr zgX=#JeSI>~{iqFI<0*eD-0rX4q{ZWfz6*6=dKz_XCSF_{^Gexz|GNBZ&g&u2ShGd& zO}BBY&I=b@l>X5Jz? zwKLP-+jHO{?j!qc&6|twZfBHcQ&pr2dtla4Mr~gH<`2V(N$;+4gB?>P&L!8@DtFOlfpuW(G#UHu) z!oBo>NBu=Uf_|Ie%Knk+o6T^2o-KPU-CPe40Ri&7l_bXgqT@mQO|S8RY{{b7@Tb8S zNSrxs0#+dhQa=%Xh9HeLga23Ie#+3Pf-#Tv7=O8nzwM(^rn2&-yy+WSqAh}6#E<6W$<;`hk!pfGWA?WQXp%Z&bR{gaZjH;vOj2{K!+j}l$q>~G0nJJ0-1 zP&j8vGAQDYDrh;U9Ed{kNC^Gd-|Sp6q;`YQ|R`L=-6l(bbtj-=}^P`TI@n zyC;}ppYbPHU6X)Fxd8fg@zY7sFZ_SLX!^zSlvK?53h`gWe(l}S3k&P*J@6^Qb0CkP znmwz1#tQhY4_JHv^}&e`U_AW4CC^6rI}GqE0_O;@#h!?HoeS~m_H)peBV*z_(xrr| zuOv_K05+HBHJ62F^Z=~CVj0{qO8^s^(Lw~D^LxSMw@?4H_56+N^}87EBc==`#_4Al z{g&#=*##A#kcz|lkRUDgADxHGIS*p(e4<2qctWJuNs8}8AErG#C4%N9r{F~g`Zv^< z{X&F)N_FE~^gCCVi0r@Hhh}0t4!Y63zx0Yc(>K4#^Vs=5sXw<59o6G9|B}C)SN^G3 zLn^&@$8lK?;CDRp!k_=Iy7>b?8vs9x zN^pR`OY^RM7a2d?34FM&C0?r^CjGDC4gTo|)*lt7v!TBGjh|1zVA{H~CFm#b4UF6K z`3*xr3@@MSe`9f@{$lkV2ykOsksjZF0sj&DF=H8>P`2M^P`CHrF#e#exv(Qu|HXFn zG}%Ai!;{NDO@nT|l}>Mm80+>TUGuhW+R|N*!;j*_knIAo?`OaHf1jo=B>uTO@Ju=b z!AlT8!TwmM&v<>ZW5y_i0!yQtk?+for6oR>u>vJOhhY`jww4C^s967M%idG=AdHed z+5~@P3Y`_&eUknIDqu;8m{TLv#48w3qBoinr~|9V!xKAnBW| z6!?nlE8;^#bq5<&(T0-r8(0(TyZC*ys0#Q%eylmU>B(f00NCsZC#$_ z$o{m-W=WU7b=5yqra-jx&sOz6Y3=;7T&N%ScxK1mD$YOZr>HKAb=dWU@D1!$@g00K z8O5(|4}^b^V3%&)`k2_`AmkUA{4);8lOvUU@HOGvoG1Qajq5(&1Ng9(+y3Nf?(h42 z-ue$){ZVqGJkZsj$^qCDnBHuRpJ}$k8CK$LOm*3dmk7;K0CdEExI5v`xpn@O51HT;D_OdI1e9>p3(R>&sR#{_3@~^lJ&o+j`5{+68{c&`i;dMZH?5& zF#QW~%z}4n{F&?T+4JBe8{`)B51!z<=R-dEfs|*6-1xJ1Ik=z@Z{>jSeEh$E|86FD z@WD&~zK8y0D^v+8iN8GYb>m;I{3i6R{cf-=TT8#^jefJarjx4D7STsV^$#gg6V(@K zokIJYqr-r!)%#}XxR>%<`dTM*3>v)14+(0KqhaaK7!ai#FmDa7Kb-)u5dXfF^ zewA6)5rT8j`a0NM%3n7Isqw4)C;Zh2DDmaC4m_x>oEN%k1mw1v>1O~SQT)pce`o*N z=~&^buVnHf8~IN+CGu+0nqYsG@t>B@XU}JcSLJaUR{jhf>T>y!>1p(%3gbTh4YM$< ze@IhvM|$`DjE_8qZN68&;!C^v`Q*yrk(Hi{ihqSV((w0>9+m!aJ%88vPd_+$|9^}B zdtaWIc<>3rbH2#;kqPx@sjnv9Kk!dCzkkoKTaRh}d4Qe$Fu?x%LiDq$0&L!*0p%NA z|Ma!?$1x=#=>MJ|CKwlBX``ww@J$L)c*nhB(KT0;`9F!_MgFS(JPZz{RD*7`Vo&KzoPR& zHnU@B22#*F-SHpJ!2iU+BGzR4FDx7Fp*n@|-w$f>Ytp|MANDd_B`ynaxRyVd=L(1} z(^E};82i5x<(~%~EeY!{(9+V8Cck#$_~#3^JKRC4E!Vgi`jpnJ@&wYp$`_y?{0EJR zCy@SlPnbVhrfbFG8u4KVL(N~ZDUE*}4sHkdUn1*FWSd9m55iII_l{tv;$OrUJ1=sH zwXibz)HAkzT066ESif|N9Y$@F_f(%4e4o+GA!9JYS|j^1ES(94Czg1dEG4I3lb_eG z{1S)1vH!5GMjbwbd{zw%WGoM9^8=6QE5;-F01udr{6l&G&cQ+SFZYAbb_;pctLFdk z4SB>!@z4*T@0xr={_Ph1SG|Zv)E|UB0Rq{Q?7Vf9M}hx(Oxjwa)3}fDU8*B<4d5@$ zu<)&LA^B$R;0GBZ@iGDWb9ZcW(}8Ga$A#kao7 z;1`-dv==h84FTnO2<%NH7K%BokNLML?^O4tt&HCA?e8z8bDfLnr;|cEYy0Ct?x4e1 z>+QQQLE_tkK>mwZEZ(q1mG4v=IkwI7E&|h(LAeOunJMdWA$iUapCJPp{wEEo9EL$a z9q+hDl!k>M0AtZ#-0%(YZZ(J~7PB$vgZ`-N_?z+9SS%_)C;Zy0qqfx;{_C-^uTc3% z{_CIuJc~SGmsHVj4~$NXnReSPKFt3CUCRjlQ?oA^U5pTUq(4@01N&?5h4=yw4jBX& ziEo8{`42rX?f3`uA$(&FyIkVEBKsA!MhI%x34UljuVRx-{ScoQe7UhdDe;LTs$vuM zKe-M+F!{LQ`MCeA>Vv4k7RL?u=lKqdkqg2h1)lqH{SBY@B6Q60cf+&vY=S9{FE7VP z>srsBjH$k4c6s4?e6hpgXSDy3mw`m*LCRMZZP#X=_jfU+;ncVBB1hmV+Voa+&?o6DB(bC*+-T7ZF+5CRiv!|FZ3jgQ~s= z{F{L9HC6G42T}m?vgdDq68k`3+pRxGc+ZK#Fh9b=FlB;%>BYO_0BF)Mi6bxhUfWyj z?6)T0ntJ>BcmMVOGs*MjQBj&xzso2!P;-};`ij5e4!mr4nElXo4DvI4x-9!)>G^+q z@ujbovES+6qxiTM_+K{kjI=lC*9Ln75J`!O`ezjjU;m}k^Ozs<%eEsNci8y@4}7Z4?HR2wfGt2>sq3|lJnJlg#8)zP{FG11l!2$OW7CI zY$eG4(W7U3X5cTg#rxDAYV_{WBO^#0@z?N7c5-Ft2%RJ@0)75Yq`;#jr;mDl!xvM( z{u(O0jKCcEI@{8@IrE+mgDD(Ie+KeyI4D>cqD$ZF}=!eI5RZJzu1sFbk5O;1fo= zPXC7Gs<@zDr|M{T=25+1b_!8R^{@L1fLi0Q5 zp&RJnDvm#j@v1wx;-A!?8pbOHi1%7f!aD!`=wo6};=g>*CRhBUV)(g85H-*0i>!a1 zkKz1^y@X zw|5)SY;OK2!}ED6NYlN9znFF@&PB-xjo%bRNBOE>-pCWhX z5M8_D1w?&Kzh(u|9$b7iBETuxMg-dbF%)!g0_m61&#O?Ve%bs(K09#yi@OyMb=gPO zw93FU{-W@eQp;nF%1?6fmF04^bB9I$=<%Tk>;oAHjz4~Cqkr5|$W^x|$aKTT;p57O zq!R_aJ-`B}ddhDBS5t)y{^8Qk#5|GN9FqQL^6%%uqc znY^EOSbsn)2k;B~p8OjoH92UBuTtW92(I^x6^@Y}F8=HA&n@)V00H{~^NaO``UP2*=rs~% zh;Clp1Lld6D{{Q>;L#h*7dr+o^Lc(hNL7=0!aWVWNC zHpC+N41eiPXL}0ruQ>;Hf;gYAbA2{sH{4%qA7lzG9$E|AI|Ov4z$*S|_}^Y>=5tox zQS!-cp^7&@UsR+96Y#Xh*6(kUfz9PGO<3f>f{5&Gw0kqcK7Xq;X#Hrx+wKh%t)~7g3!^@vl}tCE7i)yai0!{A%t@PNAQ&KPjps`LYip*ys5#zL-{ozJ8hgi+exyv1w9J zINIc&b_rx+v4(G`KZt}xqS^X)d)});AAYVMnOBXx*kG9VroelAK5+IO2A;*IJ=xTB zXJ$v{&L$m$H=dtcCy#xfPbmK&nal-2cJ-B40xD(kcXu{kYVvp5CS-r-U*YcgvZ;ZL zFse@^`AkHK^poiR+XK@N(7Yyhlfk>|kyJKYwD>7{FhH#DrI#mBXQ@9X-c+k_?y<41 z;a|93nZQOAV7`L96dx=&hp||E0w1QlkzGXfAz8$Hwg8Wh;%jBUJuo#@BHgL$^Z19# z_1p7>Jacmj0GiwL{H4X&;?$?U3IHwrpFI_ecQsJi&~$9>4^Kq#iy3{bX}sOe zv=>XW`sjJQ)Aon6Kb3!MO@lXs^4j$iBEPdME%o*2@50yOEp@f)BQ?upX5&FK9-{n! zRD*Z&X7(9Y<01BUxH|Qc5BS&WUxZn;oJ^&jO49*J{x9VpnOu_WrhPs7l_ua6ccA!@ z@dxB4D^l?vT|klKS&TGY4OLSwq_r%$8mbl_!9{1=taj6r?d|fq#2+nxY*GwFhsQf5UL*HJz$f^) zL)dt$)i=UFqfKnzx+FVTypIg6to$owCKvr4_X#biwLYppn5I7ohvK868`xb?5#UO^ zI_M9@=u0M_uK39-ZU5*K#mib-ey24E;-9Kd79jVdA3;_6LLL991W)8M_}q2pqw#5g zo=2!-G(HBnxbUr?Ykjoxv_Dvn&sTiT!rDk7*QfrCrXQ^1FYq5{+?$7)>u<7{|Ygi$wjWr<#lL(#JW{jw6V)ph~cY3u45sx z|Ax7Xz35NI`ty0J)>ZWg978;xu3I~pPe*rlaa|v5M4d=C?Jf|Wg$FRi8#@z*C+^vg z{gdgo`p+0Vs!vPdC7vI;LHxM_dptif?@2KvI*2{V_ICKdUJvO8LX!zJzoiUuy)M3{ z$7B1w8Vt`52Yh9?KI>`mWz(OP2uOL5mhBfavrN9a^ACQ8cgnvl@2Yn0>e-hT-}x#J z#@l!DDPX_QQ+*z20vpL47j)isNH_m-hp5YK!smH@5Bc)s$jFnMC0h6o@6UpMOdJ?cM_)>7Y2gqEw0h!58$%GTe*5m->rLX20o&h=@d@Bej!? zNS?Rtz4TiT!~cJpelMFn==JyC+TXt~lMw*kd$721{ha=)>c#e5o4*=uMf7!QbeszR zqfg#T1PJ|6m)rxqwDJu%e)F%n4#N9B-_YP0d#FrKR{YU%>+cZhc02UDc;D6aT?T;H z`nvPrN61h01B;$NtWy6MC$jjn!bfIPZEahRdfwTy)w5^+6UI?Bim%v*dujY+T%{gCqn5?K9b!?zs$+Vfjk_Bm8W^ilOM6aB0Hh0IKNfcBrozxLhU zPlN~le-c~&jQP0d$75#S$?FCHPJEK=@1r-IhyNP9VN3`AKh$@HFRwZefc;XV?0?%B z`Y{-TUtyVIJ=shB$6f7C44`hHu|g>R%@+f!#$Fs7Z*cU%)aF}mZtpEhKUykTc9+y0 zo&zFN|Ekp1C$zsLABIsIP@uB!SbZJsA89Z43i2LyziBT9!LV7P^;x%XF&Yeb6~wFf z2+0QwRQ3hpLG}v-fOHE6CnhGWzlf*o7E18QhMKAKql^M;^<5SL*Cle6L0R z``{|R7x8!bA1%L1?A_q?IcBN|{aF6s{fba}s89^KKND!+ljBc{f24$*N1LV&SP17G z{)dp`K7r@W9vYoc1-9P|CFi|`(Q5e01K&gaH~|}S@-fwV=f`$M`1k_&phc)FN*((N zf6{E41Y|pp{Z06hpo(x#=t;RG{E_;lkK*_GXmd@%jFiL`rMG|C@Ce<? zgxjwUpLz9_S6+EFgtw7j{0ZV8sBvug8PJutMhRm@XjpxXL&#>XZ#R(sRC#{FJ-?#a z7(X|rKOWl0Ei+J?_D8G|TmnHGdb<^Q0DWM;e`5FKq^T%;9)S_Bl9s?vr=Vne z*Ax6`BYuMLTORF0iue{}1sQpzcI6Kr#scj`et;)lve(K~Z|{Dqzfb(I9-l+}9qMop zgML9jjoyCpPwJWh$c%mrn&CE5bg_SgjScM?JUl7-HTf(_5TQW&d@|(YC+w`@JFKc! zRtL{dXS0a7{Cs~A{ITNKc2FfteduHgxTTf)c()FWk7B=izxa0H+fBruW_~<=c7S-w zcB}s|*JSaBGo0`5{{@g7ULIiWPWD@re||qnlqTPR9>_mmYp6F13Hpokd~xu%bdNos zz=^7!uJ(K^5DU!i(DHad(-a%4Jp%uM{^aFV;?^J}0f>%YSqC#SaMu;PdU*oS=*$Z<|}-EuW{ ztNPpXd@xATXps$`{1cYD0-1hL=7{L$ej}cn(NC$L$x)RVNPSk?D9Ap=zuwV?_GbFE z>E?W%=?N}!KC0gU1*$$?I9F56*ni1J58VY9iuh+soA@XF)$qJi1cnBbubKV>2R8hP zpY*Q~|7QQXm;4VX*9>3A2S3^GZhL#EAc_%k{1<4F2*;yfahf=z3rLjuW7^+&)z{`C zWZdE@=zy{UUM_Q<6M8mY+ohj}*i4t94BvmFiTSbf z-RZWDRC{ms0JXk!{)Ek-Z~V!_HuZu3`}$ftw?jX2a60OP`Lll#j8QWX`TvvtRsBl- z1+kVRRvrRLo%Z3MY;ZBx%+Xg|e3s>Jq_;knrhefkHm=_rT0d+K?7NQCN54pi1>z5c z-1I3@{9RX{Wj@O8|H7X;wQ+713UjD0a6n-SId7Xe@FHy{o95n6nE$;wCS98P<-y44K>(|*w zz%=W+zeoms!sVCki$(Y<<6pl%H{iTr{U+jD6rgJM(Y5ELJT@l2*xtTni|p^c7XyI{ zu$SCz0qc+2WY$wIxBFOZmfOP!vS+i|4CyN~XUNYF9%;(=??OXGLB;+mKk~n%-kN-S z@~y*vk@{!cJ zfn?YDS3=1jq>ghy%RevrQT!hC#jzXy1G= zqFkMWf=$Z^8_JRPP+RyTp@T}vmY_4rqs?tOGoep^gooq9OHfW_uk4julF~lMqhfC_?j+4 z#M;{S==|3=o+o@U_4I?Y)6)z{@^5kR-R{ZN+UJj&e>NUJ0l4Gh&zN7fMo^uJ;?J(J z-_f7JuUvqCq+b%=&ARHlWSKl{D~73W=0^B7Mw9USREiQQ;Qw5`2F(Ee)JeVN=mwjJ z@K3Xk;m%=*>VW)VT1Y|Ei}V%vx#-ImmZ827ehe3v2B-RoKv?lM z+CS!UA?yvY5O=$cn}9SU~)tXflQ0>ktX* zfQC?@{Gnig9$oZw{d|3W14SeUCm=$e_xE08BHm6f zqoV$srKKD2J?>v#t*)LgS5{XR_xzB3Ew;0-_w!i)dGtr>8*)_nPQFoJC;bQh=j6N8 zPu7Q3TUru=LOj?(+0TAzxW1FAwk`N@vvoD5Cz$9P-Y*IT4Hn@QaiKR|!To03s~AOQ#;jEsChBb5(?k6Zr_zp?42oBf^u`gLv*@F|C1 z3V#`?)mIC`4dYv|@ev>0KQIdG0w>L8pf3Z;;A(ad-1F)m;zk1Ggrlm85S*@A0)#mD-2+B!F&d^kgp^P>ylV9P&7GSoiL4po8f z9ngzDpP>Fst-liWFUY?uMfG`YeXgN@m;X=vG5Ot5{Be*gss}}1lpmgKPVG3AFm$-_ zloy{z@LLJ`EGdxmN5}t$bMwczVU)bwVOGi4O=|ihT)iz@5juRbtPT#TV4w9A56~-@5z;nB?wnemYn96Qbk_ zKo;m{u_y1oXYBAK?vGCw_J`1CME}2r{yzi{=jm;P9tuzQi5RD^#?J)@PkS-uZO7i; z?H1#3;9=_TQ`vQ)@?vGFvQ(YEpU(@;3?B&}IsC}@p(D}X@$`pjA#xvA{?g9O@Ai|R zpc<98dvBnCcmG{KUrm3PdTTrO87oBmP)-phtp5_VLG!|QUd+6bdF=)E6X{!4;=gz( z)c9fF@5NOejq>o!0NV%Z6z9|iD#4#5Kal)*_CL;cgd!sbae?&4& zJO<4_x6+y0Z&H>KYEhhIbNb0Ch{{Per=Q3^zK?4N1Ec^v_b)9l!+bG>G1fnC%gRkm zJM_@4#I`I$t-|vqihcBdA8)>;vk!*x1wN1Z!cjrNyj}K56yF$A`w_*ru)Z7fHz3U@ zehu~8Pk~Rdge;Q42&>1WU<-jO`BfcLk>rd+vc)yDMldKC}e6Hbt zL2l?`03~P*Ga2X=>=*6{kLJ7h8Rl2 zCrd6EmfCj>|F`;a+`^XrceQ^ulm5ZdGpGas`r5%-yF8nGSY)2an|4~k`1lYryxRFU zHTe|PKbX0(e-Z(vN)Be9KwcK#4`Ka7oma6!C)^yrxBJE;c#!AKWLQn%cNys;PzDWa z3kAXgM8R4DC~SUS-6NfRAowq^|JOMkid;Z8n3co+*4j}$mLs<_l<;QV-{qSMpZ^pW z{h^lTF-}Y10ioz`DvF@85-3ETsXlDp0SCjxSA2H>-u3d!=g$3TaWwB`yPNAqcCnRYUIQpNBj6L`I_%5asrjaLk&qX=FADG@swqO!y9{(-R zNBdCNgB^N4INWoSiqVjVPgwa?{HICupD#eZHUF&Gm)sj@2Nr*dZJj^+&iS*sv%~M? za<6KCG(s@M#}OZH{)3R*-v!LQcRO>h*^Y&R-N8t8h-uhS)laxWAO_Ksg&*;Ls0X#K zVdw&nPW-*M&7M#TYzPK@O+ua^2r$r}B|hBcPo5O`;o`r%3Ma`;%VvU$w!a|1Q8q~u zXN?`Y!KF9_tKPHvxw!q^t9M_j7yW@-&hZm7$<@c!07+qpelWjm+(LF)KhmcEFnt!F z4n$=gUWFIb4)kLVJVenUd&@Xz^ag~5(Z9H-j&7&Cns>!ftcrEO&@H~kGy_^IXB zhaz8YZ-;`H)-+7MLpDiV1tj?G@Sifl`6?jc2etmTDlJCr#0d-<@OPQ!=zWRAXs|MW zfSxz7t*5urec}mD3!iWP(P(LLMUS$)%zRSW;DPC>Ps_L+$kD&)`tz>-u4*(GfT;O2 zT4ot70>;a;nu337_|IkD;cv75wEg!L;HwnTyJP*Se)$ip6C?m2-{-{!*o-WIJ$9@a z_hu;a#=#MUW&P&`gq8$^RcPtvKT1aLxXPYQnuy`^d4y(ZyyIARyp(uylZW@>O1awq zevd#{@Hb$C^pPoU2$5o?cq1cOjFjf($t>Z2j3B}%q6UozywS=yUkr@z<$w6xT-_+L`LEH1{>opq( zPK*CZ?Tm6ndJo*|^^u=*PWPYls^d@mkn&wke8ELXfKT__>*3xIZ7NF5)gPaWQ|^tB z@9}YdK_?Czf<>=6`@cKU{HXPU4jT~%)jCK4xes~@aYi``3C;PAZg*}|99wbSM5XaYw;i4*T&wgK^gbA z@|Mu7$W~Kee@lCH@<;yN)V|NNI@I4W`wp}Y-8q-*?9BZT<~6b_)j@Qsv^ zaqjHu*CLy-K)5(xxooKM!ft6Ujd6n15ex|E-+N(;ydutFrz6K6t zO~4I$bBezSq!=x)R*DP4iHNtDi*I_&)L=15?JsRBXFg)zseg2Bf9256o&IAqYW6c9 z$90@2X?;ZgQ2KC?KjQ$dY8iUCHh$P+KXFg-UhA)%Ox~1AS^6$y;^KD_iA8{)$Ub8J zu*}(=QT+*~_L}qS_=*PqR79%x@dy@Q zrT7J56+c1g6%lVxwK;|#HldvWkRqJ|*z48nyZFbA^{dpxTjO@G#G3N+jea8o zQTC_NZ)BXy{$zq!I;bq`{AZ?r!hhmfG^PxTE9lQGq{zP$R7fq+{6OO(^4SBb?{qgN z;b)jq*5}&u^xwce>YapG4L=cIe*(5SLI7dHiGYU#W*Y)%nc- z!ZigBi@9;MdSO_uh(hc~95$FIbEcHY^|n(by$BwJ;+cLcz0A+}d_nmq9eykN3D}nu z5P~#~0cI;gNEYOOw*-BwpCJ4nr`k2w=X``eXo6BVo=+y~q^VM05qwPh^V;#DI2z}% zAJRXK0*nUOUh=#A{y%^ei#Z#Dh9Uh<^}{6pZG-cEF<*0jn*3M$fLi@Q z#iv|<9-eP446J|+^iTbi4KwgE{y!K0sL54)Nm$m#(l>)+{at@g5};@U0lcTt^R)=b zcXr3Sdq3x?fARh-^5G^JCHAZIFU8KqE4BQ-_I3)p+|M%fZ$A)j`26D8-}(M;!CzHB zSN*loE}C9cr3mPgogN^4fdbq4|s?r2!}qaD~l_u zY)E7Vj0ZQ{Udo`KVt+e;%G_)xB#+|p{rI9$$&c(0*=vv#)dyDRUt9g3=9z!3PqWQG z?Ryv>@Wo;R6+e1$eac_rzx=$^2>vP(bZeeNw@UVT^G~R~F!&Ike{O;H!i$s#c zdK@2sqzsk%-QC%#mTw3@TVts1^E`VEh1dPNF3JdXC_MC8YHQ!KZ+g1DV{4lHkW=XA zR|*xh6xf*bhm?ZXAD{!4(Qntq+;>br&_2#_|6v$i?Hl?bn|u9G{$En<9|!Ikb^Rk) zKQTv12>ZzcJ9G;M1!oWN|2fehHAXMqzyUE?d{?MHE(SUjASm_+SJ)7rJ;U>|z(Ygg zAtYXdC#90{k!(ADR`st3AHFp8Tq6E!Q}Yebk$*hdeJqY1OpQa&Tb$tUwVnV8Yy5Ft zz5t^zi{4Xh)7b*$Dd~S>`Hj*XN~vKgfHZEIp&xzcv6jIfG<;uNFnQSm|JLgRw08N_ zXDx)K3lwJ^oLOqZJ~sZH*D9J8>iBnD1@yC7;WIpgRZre>QU>%L>~9$sYYU?i;I9)O zqx!>44nfvpRUYd*y0El3cY!&TW&QZa^^L10=a{w^A zj%PxMz7z<3ix=wff{B6b6N<-Ro3Nt7h!qWIuWp#Cx0>RFnbonh)Q=dW9 zVZTalo;|y=!Y}2=`IKEk|L$=5_a3jj>F)>5{r=!D`YE7scHkuJk;>6+vl_tGW9Wa_ zL+_#>o?j$QWau=ddo~+qdy}*;8(_aRhh@>ryKNZB>+YE#Ue!s z(L4Y&rN2pmlm6Cwuz17sN&nb2*0g1d`h%oqZn(a8O0)wBDF7gz@S@u30*ARn$%}bf z{#iLlSakA>&VDB#aMIS0U&LDmkF=Ni^Ytp!ik^vg>sb2juv{(h}|l0M60 z&&8F$Pk#ihd~l0*XfW1j@=x1;+dE=WRTvbD$@_Wfd#}Tf*4J;*tzW*-1Lg8N1AH8n)jF`NOJ_6sxgI2C?=#P`^@0b2YbVnwPF@IP6gZ^)w_7Z88t;s7n zDV2pi%6?geU+N|N82;5a$6v!>V!d~vAVu`GLi&swU+QM%|50BW^4jakx~{PCDoacJ z2l6NO)IHR1rOCX@--*s=*Uxt|vGPnrLU5J_lXB41$%VFfMf#2DKNS?2H^9+?O+e7id{haM^P>WF*{Tvp?;{l zfBsAv81TZ7!!w=k$d$TINPZkVGQ&>}8DgN2UKse;=WT64&pjUa6r5{OU2rbU7lxT{ z;w#$PIzBet*4KBqLGy!xP=rG+%_xe*O*}dDDd6S(Egs@&q!2RsoL_SG2YLhXTg>rZ z-i`Wc&{}15u?mB*Sak}t-TAS}NsI3egDJJDpE`Clyinl&>-i0le%IIc3qm9Ke)K=| zk*AFK%;uA=vr>Zi>hW~-+|VnT?qK^+CIdZ0o8Op#{KJvv0T+n;PuKSMfqz_sA4Kuj z3|%EA_g%HGAN|QFEDn3Y0Fs0?5TgHr)(6!!V-3`lKS1%kMB@`}9bHT!`f+mce0g;x zpL}Bu6CGj@{TOQq~L@Zm|wC*6+xs3abB3NZ2KTwnSp;V0YpviMN+gC%UFvC+B7$v<1p&=+QND)ose zqLVqcSbtGYGmU1UZP)TbKC0fB*Y45&sdz+~NV(MhNo5YylRxEFYq3GaPD24 z7ybh)SU+!yqXjn~a{g0kjZQf>{uGz~?&bNQl}UmAggi>UurevGKcRv+fwyquNoM=fCJH+sN{!{)z?=(|u^#1MtPxpjsEwWW{c zWEcWiIE;78SkQmzF8*NO_K}d&^Jpjrj=K7Zk$#yFi^|VL`sJqYiA7~z*~VwPDe(sY z#OUPT;iC*;rtA$~K%Ff^|BB5~Y9#SJhwg#C6duFQ4gTQ7AM|iN*++oDA9=iCYphZ6 z1l6T0#8?o18eE|ND*ML(g4+J!ne<#vfe?NJK71GY)?LjUt*p;4PM`i;cFN!CsV|XV z>_OtPsWEQjAK^S&jqm4jg~DkRHsrIOuUqtO>!kJPOCY?h6XVGj1^jgLRpMzGKLuiB z+(<_)E4-2NOrD{aieZ7|rG7emfj=1QTocxBKj;7&57$F$nq``UzFdJS1v;;-ga5R7FAU?3e&)ydD`6W20!PkL0?18_Prl;}IvoQz8 zx8M(aLg~DAeDgnI->7~v<&(8~EhnTO1l0sNIVgqu3UQvV z>d`&(56`Xs;lL^inRpxcDfuNri0-(-{{w*%U+8!2nQChX;FNsxfOso~)n%pKoBVn@ z4Z=4y!El7{d`H-6HhWwXT4wzqZ816VH`ttQA2B(hfD3D0vZXb^yoln{W(@x;nvjy9 z0>8N?{)qnWC&F+JFs=w4DL+^HH-VUD_6Z>D)c*DT4Sz$wSN)$SnT~4ESG-qwS>i*; zhv8hw;`=FYr~V1qwZ3X_@XAQu8IBG%K(8~ExG?AP14$69{mn&G-+C7w8vY6Xxv+S- z{My;Y7f;W_$d-iP&EC}4M-l#1e=qiB^WUq%7RBBu#Q4R36_5Nks;`D082qQ}B72if zDItWT-^;Yu*B{uKs;_U~(yH?oUs6e1h{#`bQcg_H2Hvf21+uYfqbg9sh9sH1v!91IvlpV`(68 z7KQ+AFOa@i=5L_q?2g=Rdzc;k1KNLj#6{$Qdp`C5Iy{N}XwNTrV`<5fSJl9j=NEv^ z&N;yks~->h?QdRs;(9s+pp}&ssBM<`U6T`ET=(O1nF7o_| z&f`=9jK_2<>EC_}!kD+R0K``@an}Y5$=15?^8-&=iS3wtqqRZ2$i6ieJbZ zi&OsL5$Y?jO1}THR3Q!zCKW}m34i5by|NLHE-vw17G5|ucK`Gk$3r6{Bj7U&FtnU2 z?+S|1)O1tZmR*O*QWL<8{NkDtu}Y#+d@5zP+n+=>ZaJwG6!J$s3P()Yw>LG=AH}D{ z4gYW5HbeiJtS#M}0Ej;Ve}i`W37^6Xy{oA~1(duB$U&}>1m9yL+WdAO&1(^qL}v3_ z$$p3%f-n5>@ZYxlm?E(9QG5XSv&sKT6dzE^WYTf0Kq*9dmirYcgR2VAQhXNqAzZ@! z0$zrm=HvO-;@Rx7{sn&3(Kg%O_A&5T7|fPV=?;5dFTOuD^?q^ci~kyWK>x+K>?eLW zGx9LQzmj}6nS8ge@7-kXpW2=OlJ!MC@RRF{K3HG8pX#FP>=$9U!|L#M`w2TA3?Exb ze*6cp_&M@#7p!SkbID`P^%xq@*3_7gVO8&$9|iie?|Zt0Lk;quh{3MyWB|%4Ts3% z`p={LLNL-}sXu4(8)&%_&dnEx{xi>;nxnQ^+t3sv!M+!NGVMP)kN$#(m?{FJox3Jf zzsB4@3a}3=3#Wbp|8K4^`Yckv9EVJ!&uM*#@6l!WJo)eL z;PdnGZ9hjp?CaY%Hl9qjJlV`!lRO`lXK3I-c9iSCw=I2qc;Hra1l6|ME~+;0ya*dsjEr0T2gri*acE$-9Q$vaKSFHj1Rglc@4xZ$_}|j)%%5gpH}>@+-1ygU zhvI_bqs5%MsGSawkP&~DxQ=S3Dn={Rs56WXKoKStb9}>;vjg)bcx$qs4{!*xdT( zVcqms2yS<3%pm)_On-&>KSqsV$!&h&hfchRzia(!;>GxTlwVLhq_59J_?M8O zF1bK$hsgYtzEBYhSy->1O>NFr=tuCnHn^8qz&B^!kwv2y#Xs}nfJyOugBQ32Z#LbL z=VRf37sOt>(RkqpkbXr%hDIL*Ab4Z_1EsOg{?6Flj3SePo&&;nL2mam3InP0EKvf4 zRm7u%zSfINAgnwn$JNiXk97a_&pQi1`N6ZUKQ017@nh_*N_KMcIiiE4pX=i6J?0yS zE^HX0Wo1xF$mV4iihm~t#*(Em4U&2q;*aQj*<%#&6aE_cPe`&DA%?d0cN_<_{1-1c z_vT?*zZVbSA3wzB(|^TO{)9lEK-V|>3KpQvGsELScX~Lr=b1k(`InCx{2_j=fS)4& zBk}7Azf*93PU+jX-L_{(;P9i>m6BWp!k>)$29#%!iN!2J@8rA7=rARKJ39Ps&s4{4 zw@o#|AJDzda{+#G0Y0J%Nh%+Rij16~R>X*Tx*~knkL5O-w{YZAOQ&jFk20>D|d?jV&7w#*6<(JccC(WY^zte=Y;S{ z#1{Vh`w5=E`4+dnA{>+;^C33yeBjI3Vsl;MlQHL?#jZ`CWD>8%KiS+;-;6)91+2^o z3r+uW(!bdHeDzb}&7*zi-V5BqK?vKSui&>St??D2G{#}0CSRa%$}kh>b?zB1xWo5U zo<%8_K=<(>Fs&{gp;ze-^{Im*vbLZ{mlLXm4 z!1>zqv%`>2$WO^1z&Xi~3*Q58?@nb)P)J?{3^F0}>Cefvx|%J#p!hB}vEXIMeYPQ) zI_3p?i|QY`$_BOk4=6Lq{)i|v5WT)1mwN3E`Vl_ef0sfyqWu4IReMFRWFKiDQGMnK z`R6nPVlFHX7f^-&4D`w_8r{nvq-11=%|8!5Y2njCC^y=-o8fQr-)}tcmBNunM(#s| z(4rwMX?kngS9&+=z?``LPLGKP?Y8)g+6-BIskoR}m;X7>iw%3OYzxH;pL-SpVY$S4 zAP)EPy~PDMk2t@*p6B|lvx)kq)Lql9reEYB+>O`g$!hW0nDH+DVB`2(PP7sL0suNa z0e@9}OH&}Uegw$w^M!LKAc{O=R7(4_ zHMICZ5#Z}c|2HTZ41Gkmg-b*X*lvpubq&(EzTjlBO#OrXjrRCL&i=MX=3U> zTQcYrqmyC$5YLU54QT&=Z|$|fAsR= z%gD!&%gT1x7v*>2KLYx5!DsJLo*w^)_7B<%(;!YdDEh|!W?bTf+P^yQ77XsEcnJ8L zEGxa{mA_k`NsspUu@mUP@PCMUZSlklkVh@Q(pQ2B{hR%^j~;^@h6`tjUIo1)4^sAU zN#@l=N9yL-rc;|c_58?>pqlH!O#%Mk0nG9}>?R)m!2s|tu>eRZ^jFYXzT7Nomx9j9 zZEmxuU266zCMu7?63swvuVk%0&?_=u;qMlIgMu8@PYdQ=Q~$5^@zwm>+2J6&{m!Ev z{do)XA2R<>9d!P6;HQk-H+=O?PiWrWhkE%+thGOU9=<6UIKAij?+ZAG$$#RR-QiM9Se)7c{+isJ@;@;p`6UU)_^Nad z$UuN|^YbXEJio90J_g~!0jVFhyiD{jc z1h^w)*0aPfKcbb(Ap-xio=K?blhsPeK;dU2EmD*37U1#+MXzqy{jc;kZx7ck9rt1Gf$h^!JbcCh`$~y8ak0zSqJ~J%6A`pw(zw?w+<>F}X|QXIXfmKaD+0=b61hcE_E+ zD-rJSvl4ppAvb*CXB+h!_3yyB@E6fna%_MfE#&XOAFqo)fj1MMU`NB&V{u(yu2VZQnQp~b!S?S*zDt9< z*_)i4sw_?*17Jk*@7pI)V57rr963H~hY=7|R!Yx^jTo*d=WsRmRZ$snO)B6<{S00I z<2PL2#^2dBV9}AtUq{DXkcu6`FGx@xOK$3Xl(#lXe=mU%62GoE&97Si_-JW#>|XN7 zM^7m}67f-8Ozzb0K(+7;KOg$Ugr2b#{M?X-v$vjDxbshkE?%=f(m&1K!Q`=n$1(n0 z3LlQs9YqE!`2QSxe>qKrS%GbU{GvrsIwtvL{t2RL2&+<%^x&xcS94_3q?8YWj{; z>W(|6UrePQkMf`E5dabYzijKWG{GIncN5x9)Zhydv_g zqR)>hdg;S^u@89z#{ACg_8kL2R?fed)FrykVVXius2}p5_)s7Z1AStA@}ka|(Fa6j z{t@|iQ`r#uafI`o@0>OJ#Ss`qXcbn_ucm4I4hNn}lQGYhpNAsIVEG#NKNd5`s zhwYH~-&Nw7IvKm5P z$mK|V2Zlm@g{>I#!B4yPKfF|izv2Hk^j-?$r-)yvj%o+Qfu}^Dtm4z_?d44VF@V6z z`!2o6`uf{i)&GhDU=ANN^&u+$Bz%xfg=%tV)LyO?`N9mj02Y3sUv_WopA~xZPm>|_ z=K^38)ncwi`sq{YkALhT=*i(viPs+y9=!7Ef@qHQg}{j)Kwp6ZiMe2YYx$#A|5Jf= zyC#G!bA_9o-i7hby>0%b9&nw=KQkCi(VRCxy85(j_I^?fookk5U*H;2AeO#*&@c<$VXtLOf=OW+S~f1o|leijOI z`{TRNKv{C0^JqXEZ~%5{fPCO-q?_t6`_0GyCU_M}6Ta=-e%66l__pECJ19YH`3VL5 z78Ku|VK>vV^DDxBl-shZl!(@+e`)>{np18pOt-p_9Okr9qd4R zcIJgcDlxtJ^D5 z0zWQS;`0-^@n=sFNU@;%1=UWk-U`REH!sp zfxA0-{t^bno*xQhDJ-;@T$6!9Y~Q9>Y#Wm-{E!V!5gUfb__~QqwgL#|e}e&Gu;IbW zRn7kf-Q;-_O|WerGv7n6FBk}95VNQYEvkg|sQn#dd@X|)%GDpdRz%YXxdEC@_^_9c zx0OE9cAR(;)hGOuGx^Du$CD7Hw;92v)?E?e-JF##4GYTJ=3rk_?^zUcHU(kOQ z{x%`@X8Lb51(F{#wfLg-`NuQ=EnL`<0U-U`tdxLoxD;@4wjuFx9NYwSAC!bo2bG8&d`8;CzxZ7XjWipD-gKd{+RPS6C&sz4QZVV5|%7C3igO)#D$x_y@*~iG-`I<+}M9k^Jc^KKz~w zZy~+~t0}L-D)#t^gvX+SENgAUDE_rEL5OBUJq22~_l+9eM zjmDuQ>4$QV0}d{rK4j3JwLYrPXz}sVH?R-*vL3)lq^tHz|8LxF`pEU?4S%TlhlDR< zbyK^@Uf*W^kUStfJ@(4xMSo&Jm+S=-6|W<3oi=Wy{j@SZu(is$KR&0IAj1V^G z}zCo#f~@ zr@z4dgnVHx7cE9g?3#d zTU%BAV{BV!fRX+kg#1xvf+GDp^8XNCq3Rutv&O%gpH=K*a;0r`#Q2xVFQY#gtVD?6 zmq|=xzJW1@BWC;(o!5`EHHt|;NjPUkJm02|uiiFjhK_TO!x+4O;8(!ByX z%Emp}y|_^A10{aiGeH0Nt+ad>YWoNJWORB_K2tYv_yRClc*eyaAwMLKE&s5|-F@{~ zcK5&z!=F^YB*k-?8A<+?dM{k@A^M}X6o%2?@i-fR0%z;zN5aDR_~hZM z=jWH3o3od&zx`~xt7W&M`dt9G`s)oHER%J3o^aw^R`CNK(+9lDE7g5cJLuI+2Cyj# zFVT7DtYHZ({)5})I+N8Viv~dd^YCu$L*d_>sIQkk$oQ)~3AU$frW5x3COdh4$N!{$ zK>}gu;)`GnJD?REMf5LiTnGLRnSRA?EjFe1Oteb7m41$WoWyQjODs;DK!3Rw-%);~ z#c!_n7f7%H?`W=TzJq})JO}=>^f!GM`~C(M(E6JVL-ZT)P1ciR4wcdz?GE-FPBsxC z)8D`IB=NNwzLp5m;Y;z4#D930M!B4IS2g|y_m1T63$o9#59z--NqKuektVrx+WJR}yl^p+KPww) zzvfS>lhaX=4{WT%!#I)EUL>Rb0M(h7{@MG{7+?Ftfe)|`y{EnP{yNl8>nr|8@8|s# zAngBnCi4ZxH=CNBzUu$G{yZETxA~_uDGIqIe(Q$*-NZK@CQ54yB$^Wa!#>zWw!x5J zo5`!&b-1HF%|tl=rtI75^l+K@ny)ebxK((CMGzzmy{>fzE_96qMf4Gq9Ch(}z||m> zei9L&zcgd`71AZhT6?$LArv6aqxm==J7hZK#hS(rAO1Y?XNRYM=cM!v>U?L%2bj!( z2QINc@n7yC^oo^t{hxrJUI!7ReuS$Z1NBMvl%_rxZ`@lq%k9guzpLN;M{mu)*lqa3 zDMGi^e>l|v0};CET6{J#5{(}fqot*T;^S_7Y#>g!m+&Tu?^^zZ;?JO3&7}Kb^~pEp zPa~P=&;SJ>-$zbkpHaU&s*k3KAI2A_b+8MrQapLR>fhWt-n{kJaZ=Df=K+3OftPQ= zoW!5%XaLZR^?&PN08;CD&CSnJe}-daWqI`#uEzlj!0m58Ja|LdL0b;rf~gT-mF&E2 zoJbSoEAN8AAs$|{eX8eqn)B^LQ)xXK@z3+v$pCv1KBo9@;uqDw7^3Ibw#!r)TTX%F z>=-%S=*0`!?s(l}Y#qYmh$>t)e`>BfpZ(Ez*6@qbwp%rY4Nts9Q# zErbO(R^uu92c%N(O-{Xc`0y`N9dBBEl@bUL0e$1!b`f)ZU4KY%AGBX$;J+~PS&JX> z$*h^A06c|jx{oqDVw^YmHc@rTFVnq~H2*{i*M9<`nf+mJfPYKBxj+t8&HhkSDQ2sT z7(c+jhkjmng*hfnW?{Yze>U`;VdwyFMEOy0gP3>_T)=*X_uS;?L)D;>{y=Xb|4n+- zUlyCbLds=Na2M+3T|rM!5`+ELrTPC#0PTOBzcgPp|52Ps=TcL%2@K-`!P7PT zLcB{kpyGd(bTw@$_~zfIJ!U%BMiJZ8c4k-WT@v{s4PSW$|DWgs1T?a5lwZL+GV9VY66DF?r}d%QHR0Jk{v|I-3rCS4-=0zRhpi=+o30$E?|emDR%j>cZ3 z{~4I{EY`c=X)!?dpRo6!n%(n#8rWa-GUgvuURDR|8F~rgvm)$L8xDJx`tQ_lR+$s+ zZ@7Q_xkQ%U!j8tdYWv5A4o~#$KoYE&Rjzcklo=T%qzN0SH{i@O78g*VObIQV+1-flhFLnE2%9cE#_c zVs$4#7ok${yKR@^#lYx8)KR6q%z*<4kJ0Wz?!my;f zj#abIaf**g)3E;@X8nUwVVU*Rau-fJ{!fS!>tY4qsgG>LZQ=899{N)!(Bxvx(odlu zoJtuX*Kv^#&jEheR9DZw?*>E_mzj&F8=7~s#G;of>gVP=O?QvG_(%P1B+eu${*n3~ z2?9japO;NO>hT#hC_~{4f-^JVI?CTn=Q=6F)l3aq87CDGW6~p)Az5NRTzv4X-`=+M za}bzumeHl-_x>`fzhnJ-+J>g#J}LHB6kAlQ&%*;;lfVuCP<-J!e(2~6!Gszv^WM=H zZ;AYuW?$oi9##(7DE7;B{Ev;H_{~jbz=*%P_|5OzK4+s#KO4#V-c7!ycZBDkn_qZT z`hzqe^oyu}mx~XT|7*CQ{s3P!MRpGUPJTN)KoBz;j*V}^Vo2&hAy}XF`V=l~4{uZU zHH9u#MIuBT>}46*LJ5gK1o#pY>c7eN($dn4FMi!?BuloxzgP0{nDBLgw%UK}-~(O^ z!lZav3hTCm8dYp?jB6C%cZo3X{Xd&M5))=S+CH{-YDyU}?cUE0^OgB^=7aC*YX|ug zEsez;ZCFtXWW3KyzVY=pCN7r0elfD&85{O*hHn7`tasHvljk|NmF1}czu~-6dxM?X zo(%R5=glIV|8VuvYk&L<<8_}#2Xpb0K|b_`9hc8!Tzw(*?^*&NGGFsz2lJ2p2u&ON z^Q_9DS1w!sTJj6A)e*cXJ@gCd&GilS-7WhJ-$|&@;5B}Z4*o=+H^Mf z8N7g=Th{!SR9UD-U$`=s2}IrG-o{O=zeS1`eyOhiudTC-ZL2)v__32VC#7p_Cv5_x zloLp6WSD5X7BfZ&T-OiJ8@b&$LE~)ectE$>z(^Q@hJ){LlM?` z*W=MB_)~Mn_m4-RuH@K1B=5T>2HLUz1|Dqf$qq|Cm3hWB9y2u(&d;19B#Jx>|6zQX zVEmM8BjP_`!hDebF8wRMNk1}=u!Br%FvS7f))a+xyh0uiUnw~=V>4u&j?Fwje3X6? znbNxj*c8De9gFzuG2P!^yz4K(Newp|pbvIC?(K9?zS&>{`!3gf{=y%8 zyBMe`+&@h2Gd<_*GWg_2YE_$oIl^lFFy;zXtfr(1AgPWUp51=iuP=! zH?Wy>@Ax+Gli)^lEn1a+w>bWVmbys6zMRh(ZuBnz!DHUz*QQSf@eRA4tJ~VWUcUi- zfa@csANtjb=p)AzHV){i+A+sH>IY}ox*5MYR;1Cn=;sD`ZB-hmCE+jVB(cPRZ4PPr z8|ypqVq=xfA=ktDSRSE(CH)V8E%E~dt^H;S86@|xzd?7}1HK}Q+H< z2Ilt|PtIfiWvgB!)&qa3R%#;$)>;(clm8>=?`8D~xR>!qD6@Z&>FyZb zA9d;666jYj@A2{TOC3(AUul0%k~bsGYHySFdH${VzhyKVYwa7q&HAIZJ?YSSW@$YS z^m&br9tA#KvC{*0?z(gTgC5{_n4MpZeYu?=gkL!J4(Cg3Fns?5c<~G0-RkK6x4_3e z%LbRR*x*58kRSo)$$KjlUiKy93g^&|W@f%_A#m;B-41%-96&ViBS?WCLOgr9&3MYB z;9LBI`i_gTU+VciN)+0oAf0?WXuha_@i_8M`?ED{c^Yq5e3$a?yxQjS&D8?qK5#Fa z4s6DK$U&t8v%hTq{=(!q>}^E!Ve7Z#p77Tj-`)2|{C+gW?nG-6ezM57=nv`-Bff

GyQ$xxyMzR=Bd_b{buLbR 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 +#include "apilib.h" + +void HariMain(void) +{ + char *buf, s[12]; + int win, timer, sec = 0, min = 0, hou = 0; + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "noodle"); + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (;;) { + sprintf(s, "%5d:%02d:%02d", hou, min, sec); + api_boxfilwin(win, 28, 27, 115, 41, 7);/*白色*/ + api_putstrwin(win, 28, 27, 0, 11, s); /*黑色*/ + api_settimer(timer, 100); /* 1秒 */ + if (api_getkey(1) != 128) { + break; + } + sec++; + if (sec == 60) { + sec = 0; + min++; + if (min == 60) { + min = 0; + hou++; + } + } + } + api_end(); +} diff --git a/29_day/sosu/!cons_9x.bat b/29_day/sosu/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/sosu/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/sosu/!cons_nt.bat b/29_day/sosu/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/sosu/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/sosu/Makefile b/29_day/sosu/Makefile new file mode 100644 index 0000000..de7b705 --- /dev/null +++ b/29_day/sosu/Makefile @@ -0,0 +1,5 @@ +APP = sosu +STACK = 2k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/sosu/make.bat b/29_day/sosu/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/sosu/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/sosu/sosu.c b/29_day/sosu/sosu.c new file mode 100644 index 0000000..6b9a997 --- /dev/null +++ b/29_day/sosu/sosu.c @@ -0,0 +1,24 @@ +#include +#include "apilib.h" + +#define MAX 1000 + +void HariMain(void) +{ + char flag[MAX], s[8]; + int i, j; + for (i = 0; i < MAX; i++) { + flag[i] = 0; + } + for (i = 2; i < MAX; i++) { + if (flag[i] == 0) { + /*没有标记的为质数*/ + sprintf(s, "%d ", i); + api_putstr0(s); + for (j = i * 2; j < MAX; j += i) { + flag[j] = 1; /*给它的倍数做上标记*/ + } + } + } + api_end(); +} diff --git a/29_day/sosu2/!cons_9x.bat b/29_day/sosu2/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/sosu2/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/sosu2/!cons_nt.bat b/29_day/sosu2/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/sosu2/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/sosu2/Makefile b/29_day/sosu2/Makefile new file mode 100644 index 0000000..d97a733 --- /dev/null +++ b/29_day/sosu2/Makefile @@ -0,0 +1,5 @@ +APP = sosu2 +STACK = 11k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/sosu2/make.bat b/29_day/sosu2/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/sosu2/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/sosu2/sosu2.c b/29_day/sosu2/sosu2.c new file mode 100644 index 0000000..381e436 --- /dev/null +++ b/29_day/sosu2/sosu2.c @@ -0,0 +1,24 @@ +#include +#include "apilib.h" + +#define MAX 10000 + +void HariMain(void) +{ + char flag[MAX], s[8]; + int i, j; + for (i = 0; i < MAX; i++) { + flag[i] = 0; + } + for (i = 2; i < MAX; i++) { + if (flag[i] == 0) { + /*没有标记的为质数*/ + sprintf(s, "%d ", i); + api_putstr0(s); + for (j = i * 2; j < MAX; j += i) { + flag[j] = 1; /*给它的倍数做上标记*/ + } + } + } + api_end(); +} diff --git a/29_day/sosu3/!cons_9x.bat b/29_day/sosu3/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/sosu3/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/sosu3/!cons_nt.bat b/29_day/sosu3/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/sosu3/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/sosu3/Makefile b/29_day/sosu3/Makefile new file mode 100644 index 0000000..a7e9900 --- /dev/null +++ b/29_day/sosu3/Makefile @@ -0,0 +1,5 @@ +APP = sosu3 +STACK = 1k +MALLOC = 42k + +include ../app_make.txt diff --git a/29_day/sosu3/make.bat b/29_day/sosu3/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/sosu3/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/sosu3/sosu3.c b/29_day/sosu3/sosu3.c new file mode 100644 index 0000000..db4527b --- /dev/null +++ b/29_day/sosu3/sosu3.c @@ -0,0 +1,26 @@ +#include +#include "apilib.h" + +#define MAX 10000 + +void HariMain(void) +{ + char *flag, s[8]; + int i, j; + api_initmalloc(); + flag = api_malloc(MAX); + for (i = 0; i < MAX; i++) { + flag[i] = 0; + } + for (i = 2; i < MAX; i++) { + if (flag[i] == 0) { + /*没有标记的为质数*/ + sprintf(s, "%d ", i); + api_putstr0(s); + for (j = i * 2; j < MAX; j += i) { + flag[j] = 1; /*给它的倍数做上标记*/ + } + } + } + api_end(); +} diff --git a/29_day/star1/!cons_9x.bat b/29_day/star1/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/star1/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/star1/!cons_nt.bat b/29_day/star1/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/star1/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/star1/Makefile b/29_day/star1/Makefile new file mode 100644 index 0000000..ae4cd72 --- /dev/null +++ b/29_day/star1/Makefile @@ -0,0 +1,5 @@ +APP = star1 +STACK = 1k +MALLOC = 47k + +include ../app_make.txt diff --git a/29_day/star1/make.bat b/29_day/star1/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/star1/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/star1/star1.c b/29_day/star1/star1.c new file mode 100644 index 0000000..93241a8 --- /dev/null +++ b/29_day/star1/star1.c @@ -0,0 +1,18 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "star1"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + api_point(win, 75, 59, 3);/*黄色*/ + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/29_day/stars/!cons_9x.bat b/29_day/stars/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/stars/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/stars/!cons_nt.bat b/29_day/stars/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/stars/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/stars/Makefile b/29_day/stars/Makefile new file mode 100644 index 0000000..899cc8f --- /dev/null +++ b/29_day/stars/Makefile @@ -0,0 +1,5 @@ +APP = stars +STACK = 1k +MALLOC = 47k + +include ../app_make.txt diff --git a/29_day/stars/make.bat b/29_day/stars/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/stars/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/stars/stars.c b/29_day/stars/stars.c new file mode 100644 index 0000000..19c54e5 --- /dev/null +++ b/29_day/stars/stars.c @@ -0,0 +1,24 @@ +#include "apilib.h" + +int rand(void); /*产生0~32767之间的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win, x, y, 3);/*黄色*/ + } + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/29_day/stars2/!cons_9x.bat b/29_day/stars2/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/stars2/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/stars2/!cons_nt.bat b/29_day/stars2/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/stars2/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/stars2/Makefile b/29_day/stars2/Makefile new file mode 100644 index 0000000..77c18cd --- /dev/null +++ b/29_day/stars2/Makefile @@ -0,0 +1,5 @@ +APP = stars2 +STACK = 1k +MALLOC = 47k + +include ../app_make.txt diff --git a/29_day/stars2/make.bat b/29_day/stars2/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/stars2/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/stars2/stars2.c b/29_day/stars2/stars2.c new file mode 100644 index 0000000..6c63c19 --- /dev/null +++ b/29_day/stars2/stars2.c @@ -0,0 +1,25 @@ +#include "apilib.h" + +int rand(void); /*产生0~32767的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars2"); + api_boxfilwin(win + 1, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win + 1, x, y, 3);/*黄色*/ + } + api_refreshwin(win, 6, 26, 144, 94); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/29_day/type/!cons_9x.bat b/29_day/type/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/type/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/type/!cons_nt.bat b/29_day/type/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/type/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/type/Makefile b/29_day/type/Makefile new file mode 100644 index 0000000..7314b7b --- /dev/null +++ b/29_day/type/Makefile @@ -0,0 +1,5 @@ +APP = type +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/type/make.bat b/29_day/type/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/type/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/type/type.c b/29_day/type/type.c new file mode 100644 index 0000000..c6fc99f --- /dev/null +++ b/29_day/type/type.c @@ -0,0 +1,23 @@ +#include "apilib.h" + +void HariMain(void) +{ + int fh; + char c, cmdline[30], *p; + + api_cmdline(cmdline, 30); + for (p = cmdline; *p > ' '; p++) { } /*跳过之前的内容,直到遇到空格*/ + for (; *p == ' '; p++) { } /*跳过空格*/ + fh = api_fopen(p); + if (fh != 0) { + for (;;) { + if (api_fread(&c, 1, fh) == 0) { + break; + } + api_putchar(c); + } + } else { + api_putstr0("File not found.\n"); + } + api_end(); +} diff --git a/29_day/typeipl/!cons_9x.bat b/29_day/typeipl/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/typeipl/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/typeipl/!cons_nt.bat b/29_day/typeipl/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/typeipl/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/typeipl/Makefile b/29_day/typeipl/Makefile new file mode 100644 index 0000000..f5b423e --- /dev/null +++ b/29_day/typeipl/Makefile @@ -0,0 +1,5 @@ +APP = typeipl +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/typeipl/make.bat b/29_day/typeipl/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/typeipl/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/typeipl/typeipl.c b/29_day/typeipl/typeipl.c new file mode 100644 index 0000000..90a0273 --- /dev/null +++ b/29_day/typeipl/typeipl.c @@ -0,0 +1,17 @@ +#include "apilib.h" + +void HariMain(void) +{ + int fh; + char c; + fh = api_fopen("ipl10.nas"); + if (fh != 0) { + for (;;) { + if (api_fread(&c, 1, fh) == 0) { + break; + } + api_putchar(c); + } + } + api_end(); +} diff --git a/29_day/walk/!cons_9x.bat b/29_day/walk/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/walk/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/walk/!cons_nt.bat b/29_day/walk/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/walk/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/walk/Makefile b/29_day/walk/Makefile new file mode 100644 index 0000000..641c368 --- /dev/null +++ b/29_day/walk/Makefile @@ -0,0 +1,5 @@ +APP = walk +STACK = 1k +MALLOC = 48k + +include ../app_make.txt diff --git a/29_day/walk/make.bat b/29_day/walk/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/walk/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/walk/walk.c b/29_day/walk/walk.c new file mode 100644 index 0000000..4772f8a --- /dev/null +++ b/29_day/walk/walk.c @@ -0,0 +1,26 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "walk"); + api_boxfilwin(win, 4, 24, 155, 95, 0);/*黑色*/ + x = 76; + y = 56; + api_putstrwin(win, x, y, 3, 1, "*");/*黄色*/ + for (;;) { + i = api_getkey(1); + api_putstrwin(win, x, y, 0 , 1, "*"); /*用黑色擦除*/ + if (i == '4' && x > 4) { x -= 8; } + if (i == '6' && x < 148) { x += 8; } + if (i == '8' && y > 24) { y -= 8; } + if (i == '2' && y < 80) { y += 8; } + if (i == 0x0a) { break; } /*按回车键结束*/ + api_putstrwin(win, x, y, 3 , 1, "*");/*黄色*/ + } + api_closewin(win); + api_end(); +} diff --git a/29_day/winhelo/!cons_9x.bat b/29_day/winhelo/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/winhelo/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/winhelo/!cons_nt.bat b/29_day/winhelo/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/winhelo/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/winhelo/Makefile b/29_day/winhelo/Makefile new file mode 100644 index 0000000..44ac359 --- /dev/null +++ b/29_day/winhelo/Makefile @@ -0,0 +1,5 @@ +APP = winhelo +STACK = 8k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/winhelo/make.bat b/29_day/winhelo/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/winhelo/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/winhelo/winhelo.c b/29_day/winhelo/winhelo.c new file mode 100644 index 0000000..c36e988 --- /dev/null +++ b/29_day/winhelo/winhelo.c @@ -0,0 +1,15 @@ +#include "apilib.h" + +void HariMain(void) +{ + int win; + char buf[150 * 50]; + + win = api_openwin(buf, 150, 50, -1, "hello"); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/29_day/winhelo2/!cons_9x.bat b/29_day/winhelo2/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/winhelo2/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/winhelo2/!cons_nt.bat b/29_day/winhelo2/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/winhelo2/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/winhelo2/Makefile b/29_day/winhelo2/Makefile new file mode 100644 index 0000000..a1544f5 --- /dev/null +++ b/29_day/winhelo2/Makefile @@ -0,0 +1,5 @@ +APP = winhelo2 +STACK = 8k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/winhelo2/make.bat b/29_day/winhelo2/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/winhelo2/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/winhelo2/winhelo2.c b/29_day/winhelo2/winhelo2.c new file mode 100644 index 0000000..dfc4ce7 --- /dev/null +++ b/29_day/winhelo2/winhelo2.c @@ -0,0 +1,17 @@ +#include "apilib.h" + +void HariMain(void) +{ + int win; + char buf[150 * 50]; + + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 3); /*黄色*/ + api_putstrwin(win, 28, 28, 0 /*黑色*/, 12, "hello, world"); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/29_day/winhelo3/!cons_9x.bat b/29_day/winhelo3/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/winhelo3/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/winhelo3/!cons_nt.bat b/29_day/winhelo3/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/winhelo3/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/winhelo3/Makefile b/29_day/winhelo3/Makefile new file mode 100644 index 0000000..719b23a --- /dev/null +++ b/29_day/winhelo3/Makefile @@ -0,0 +1,5 @@ +APP = winhelo3 +STACK = 1k +MALLOC = 40k + +include ../app_make.txt diff --git a/29_day/winhelo3/make.bat b/29_day/winhelo3/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/winhelo3/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/winhelo3/winhelo3.c b/29_day/winhelo3/winhelo3.c new file mode 100644 index 0000000..a1529e5 --- /dev/null +++ b/29_day/winhelo3/winhelo3.c @@ -0,0 +1,19 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win; + + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 6); /*浅蓝色*/ + api_putstrwin(win, 28, 28, 0 , 12, "hello, world");/*黑色*/ + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} From 41a0252634dc00686e2f25570a52b7efc9b64229 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Thu, 19 May 2016 12:27:28 +0800 Subject: [PATCH 55/83] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 29_day/haribote/window.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/29_day/haribote/window.c b/29_day/haribote/window.c index 4d70578..df9165c 100644 --- a/29_day/haribote/window.c +++ b/29_day/haribote/window.c @@ -66,9 +66,15 @@ void make_wtitle8(unsigned char *buf, int xsize, char *title, char act) void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l) { + struct TASK *task = task_now(); boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15); - putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); - sheet_refresh(sht, x, y, x + l * 8, y + 16); + if (task->langmode != 0 && task->langbyte1 != 0) { + putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); + sheet_refresh(sht, x - 8, y, x + l * 8, y + 16); + } else { + putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); + sheet_refresh(sht, x, y, x + l * 8, y + 16); + } return; } From 633089d320b2be09708b9cc89085040cf8073624 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Thu, 19 May 2016 13:01:06 +0800 Subject: [PATCH 56/83] =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=8E=8B=E7=BC=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 29_day/app_make.txt | 16 +- 29_day/haribote/Makefile | 2 +- 29_day/haribote/bootpack.c | 8 +- 29_day/haribote/bootpack.h | 5 + 29_day/haribote/console.c | 14 +- 29_day/haribote/file.c | 20 ++ 29_day/haribote/tek.c | 646 ++++++++++++++++++++++++++++++++++++ 29_day/hello4/Makefile | 3 + 29_day/hello5/Makefile | 3 + 29_day/nihongo/nihongo.fnt | Bin 145472 -> 58009 bytes 29_day/nihongo/nihongo.org | Bin 0 -> 145472 bytes 29_day/tek/autodec_.c | 649 +++++++++++++++++++++++++++++++++++++ 29_day/tek/tek.c | 646 ++++++++++++++++++++++++++++++++++++ 29_day/winhelo/Makefile | 4 + 14 files changed, 2000 insertions(+), 16 deletions(-) create mode 100644 29_day/haribote/tek.c create mode 100644 29_day/nihongo/nihongo.org create mode 100644 29_day/tek/autodec_.c create mode 100644 29_day/tek/tek.c diff --git a/29_day/app_make.txt b/29_day/app_make.txt index 2bca4bc..30421f4 100644 --- a/29_day/app_make.txt +++ b/29_day/app_make.txt @@ -11,6 +11,7 @@ OBJ2BIM = $(TOOLPATH)obj2bim.exe MAKEFONT = $(TOOLPATH)makefont.exe BIN2OBJ = $(TOOLPATH)bin2obj.exe BIM2HRB = $(TOOLPATH)bim2hrb.exe +BIM2BIN = $(TOOLPATH)bim2bin.exe RULEFILE = ../haribote.rul EDIMG = $(TOOLPATH)edimg.exe IMGTOL = $(TOOLPATH)imgtol.com @@ -29,15 +30,13 @@ $(APP).bim : $(APP).obj $(APILIBPATH)apilib.lib Makefile ../app_make.txt $(OBJ2BIM) @$(RULEFILE) out:$(APP).bim map:$(APP).map stack:$(STACK) \ $(APP).obj $(APILIBPATH)apilib.lib -$(APP).hrb : $(APP).bim Makefile ../app_make.txt - $(BIM2HRB) $(APP).bim $(APP).hrb $(MALLOC) - -haribote.img : ../haribote/ipl10.bin ../haribote/haribote.sys $(APP).hrb \ +haribote.img : ../haribote/ipl20.bin ../haribote/haribote.sys $(APP).hrb \ Makefile ../app_make.txt $(EDIMG) imgin:../../z_tools/fdimg0at.tek \ - wbinimg src:../haribote/ipl10.bin len:512 from:0 to:0 \ + wbinimg src:../haribote/ipl20.bin len:512 from:0 to:0 \ copy from:../haribote/haribote.sys to:@: \ copy from:$(APP).hrb to:@: \ + copy from:../nihongo/nihongo.fnt to:@: \ imgout:haribote.img #一般规则 @@ -51,6 +50,12 @@ haribote.img : ../haribote/ipl10.bin ../haribote/haribote.sys $(APP).hrb \ %.obj : %.nas Makefile ../app_make.txt $(NASK) $*.nas $*.obj $*.lst +%.org : %.bim Makefile ../app_make.txt + $(BIM2HRB) $*.bim $*.org $(MALLOC) + +%.hrb : %.org Makefile ../app_make.txt + $(BIM2BIN) -osacmp in:$*.org out:$*.hrb + #命令 run : @@ -72,6 +77,7 @@ clean : -$(DEL) *.obj -$(DEL) *.map -$(DEL) *.bim + -$(DEL) *.org -$(DEL) haribote.img src_only : diff --git a/29_day/haribote/Makefile b/29_day/haribote/Makefile index 374bba7..a5dd10c 100644 --- a/29_day/haribote/Makefile +++ b/29_day/haribote/Makefile @@ -1,6 +1,6 @@ OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \ int.obj fifo.obj keyboard.obj mouse.obj memory.obj sheet.obj timer.obj \ - mtask.obj window.obj console.obj file.obj + mtask.obj window.obj console.obj file.obj tek.obj TOOLPATH = ../../z_tools/ INCPATH = ../../z_tools/haribote/ diff --git a/29_day/haribote/bootpack.c b/29_day/haribote/bootpack.c index 92754c6..4a0000b 100644 --- a/29_day/haribote/bootpack.c +++ b/29_day/haribote/bootpack.c @@ -106,15 +106,17 @@ void HariMain(void) fifo32_put(&keycmd, key_leds); /* 载入nihongo.fnt */ - nihongo = (unsigned char *) memman_alloc_4k(memman, 16 * 256 + 32 * 94 * 47); fat = (int *) memman_alloc_4k(memman, 4 * 2880); file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); + finfo = file_search("nihongo.fnt", (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); if (finfo != 0) { - file_loadfile(finfo->clustno, finfo->size, nihongo, fat, (char *) (ADR_DISKIMG + 0x003e00)); + i = finfo->size; + nihongo = file_loadfile2(finfo->clustno, &i, fat); } else { + nihongo = (unsigned char *) memman_alloc_4k(memman, 16 * 256 + 32 * 94 * 47); for (i = 0; i < 16 * 256; i++) { - nihongo[i] = hankaku[i]; /* 没有字库,半角部分直接复制英文字库 */ + nihongo[i] = hankaku[i]; /*没有字库,半角部分直接复制英文字库*/ } for (i = 16 * 256; i < 16 * 256 + 32 * 94 * 47; i++) { nihongo[i] = 0xff; /* 没有字库,全角部分以0xff填充 */ diff --git a/29_day/haribote/bootpack.h b/29_day/haribote/bootpack.h index f2e8243..bb195ff 100644 --- a/29_day/haribote/bootpack.h +++ b/29_day/haribote/bootpack.h @@ -286,7 +286,12 @@ struct FILEINFO { void file_readfat(int *fat, unsigned char *img); void file_loadfile(int clustno, int size, char *buf, int *fat, char *img); struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max); +char *file_loadfile2(int clustno, int *psize, int *fat); /* bootpack.c */ struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal); struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal); + +/* tek.c */ +int tek_getsize(unsigned char *p); +int tek_decomp(unsigned char *p, char *q, int size); diff --git a/29_day/haribote/console.c b/29_day/haribote/console.c index b231d2b..44047b0 100644 --- a/29_day/haribote/console.c +++ b/29_day/haribote/console.c @@ -350,7 +350,7 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; char name[18], *p, *q; struct TASK *task = task_now(); - int i, segsiz, datsiz, esp, dathrb; + int i, segsiz, datsiz, esp, dathrb, appsiz; struct SHTCTL *shtctl; struct SHEET *sht; @@ -376,10 +376,10 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) } if (finfo != 0) { - /*找到文件的情况*/ - p = (char *) memman_alloc_4k(memman, finfo->size); - file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00)); - if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) { + /*如果找到文件*/ + appsiz = finfo->size; + p = file_loadfile2(finfo->clustno, &appsiz, fat); + if (appsiz >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) { segsiz = *((int *) (p + 0x0000)); esp = *((int *) (p + 0x000c)); datsiz = *((int *) (p + 0x0010)); @@ -412,7 +412,7 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) } else { cons_putstr0(cons, ".hrb file format error.\n"); } - memman_free_4k(memman, (int) p, finfo->size); + memman_free_4k(memman, (int) p, appsiz); cons_newline(cons); return 1; } @@ -566,7 +566,7 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int fh->buf = (char *) memman_alloc_4k(memman, finfo->size); fh->size = finfo->size; fh->pos = 0; - file_loadfile(finfo->clustno, finfo->size, fh->buf, task->fat, (char *) (ADR_DISKIMG + 0x003e00)); + file_loadfile2(finfo->clustno, &fh->size, task->fat); } } } else if (edx == 22) { diff --git a/29_day/haribote/file.c b/29_day/haribote/file.c index bf9d063..a4bf405 100644 --- a/29_day/haribote/file.c +++ b/29_day/haribote/file.c @@ -72,3 +72,23 @@ struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max) } return 0; /*没有找到*/ } + +char *file_loadfile2(int clustno, int *psize, int *fat) +{ + int size = *psize, size2; + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + char *buf, *buf2; + buf = (char *) memman_alloc_4k(memman, size); + file_loadfile(clustno, size, buf, fat, (char *) (ADR_DISKIMG + 0x003e00)); + if (size >= 17) { + size2 = tek_getsize(buf); + if (size2 > 0) { /*使用tek格式压缩的文件*/ + buf2 = (char *) memman_alloc_4k(memman, size2); + tek_decomp(buf, buf2, size2); + memman_free_4k(memman, (int) buf, size); + buf = buf2; + *psize = size2; + } + } + return buf; +} diff --git a/29_day/haribote/tek.c b/29_day/haribote/tek.c new file mode 100644 index 0000000..4062dcc --- /dev/null +++ b/29_day/haribote/tek.c @@ -0,0 +1,646 @@ +#include "bootpack.h" +#include +#include +#define NULL 0 + +typedef unsigned char UCHAR; +typedef unsigned int UINT32; +typedef UINT32 tek_TPRB; + +static int tek_decode1(int siz, UCHAR *p, UCHAR *q); +static int tek_decode2(int siz, UCHAR *p, UCHAR *q); +static int tek_decode5(int siz, UCHAR *p, UCHAR *q); + +static unsigned int tek_getnum_s7s(UCHAR **pp) +{ + unsigned int s = 0; + UCHAR *p = *pp; + do { + s = s << 7 | *p++; + } while ((s & 1) == 0); + s >>= 1; + *pp = p; + return s; +} + +int tek_getsize(unsigned char *p) +{ + static char header[15] = { + 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x41, 0x53, 0x4b, 0x43, 0x4d, 0x50 + }; + int size = -1; + if (memcmp(p + 1, header, 15) == 0 && (*p == 0x83 || *p == 0x85 || *p == 0x89)) { + p += 16; + size = tek_getnum_s7s(&p); + } + return size; +} /* (注)memcmp和strncmp差不多,这个函数忽略字符串中的0并一直比较到指定的15个字符为止*/ + +int tek_decomp(unsigned char *p, char *q, int size) +{ + int err = -1; + if (*p == 0x83) { + err = tek_decode1(size, p, q); + } else if (*p == 0x85) { + err = tek_decode2(size, p, q); + } else if (*p == 0x89) { + err = tek_decode5(size, p, q); + } + if (err != 0) { + return -1; /*失败*/ + } + return 0; /*成功*/ +} + +static int tek_lzrestore_stk1(int srcsiz, UCHAR *src, int outsiz, UCHAR *q) +{ + int by, lz, cp, ds; + UCHAR *q1 = q + outsiz, *s7ptr = src, *q0 = q; + do { + if ((by = (lz = *s7ptr++) & 0x0f) == 0) + by = tek_getnum_s7s(&s7ptr); + if ((lz >>= 4) == 0) + lz = tek_getnum_s7s(&s7ptr); + do { + *q++ = *s7ptr++; + } while (--by); + if (q >= q1) + break; + do { + ds = (cp = *s7ptr++) & 0x0f; + if ((ds & 1) == 0) { + do { + ds = ds << 7 | *s7ptr++; + } while ((ds & 1) == 0); + } + ds = ~(ds >> 1); + if ((cp >>= 4) == 0) { + do { + cp = cp << 7 | *s7ptr++; + } while ((cp & 1) == 0); + cp >>= 1; + } + cp++; + if (q + ds < q0) + goto err; + if (q + cp > q1) + cp = q1 - q; + do { + *q = *(q + ds); + q++; + } while (--cp); + } while (--lz); + } while (q < q1); + return 0; +err: + return 1; +} + +static int tek_decode1(int siz, UCHAR *p, UCHAR *q) +{ + int dsiz, hed, bsiz; + UCHAR *p1 = p + siz; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (dsiz > bsiz || (hed & 0x21) != 0x01) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + if (tek_getnum_s7s(&p) != 0) + return 1; + return tek_lzrestore_stk1(p1 - p, p, dsiz, q); + } + return 0; +} + +static unsigned int tek_getnum_s7(UCHAR **pp) +{ + unsigned int s = 0, b = 0, a = 1; + UCHAR *p = *pp; + for (;;) { + s = s << 7 | *p++; + if (s & 1) + break; + a <<= 7; + b += a; + } + s >>= 1; + *pp = p; + return s + b; +} + +static int tek_lzrestore_stk2(int srcsiz, UCHAR *src, int outsiz, UCHAR *q) +{ + int cp, ds, repdis[4], i, j; + UCHAR *q1 = q + outsiz, *s7ptr = src, *q0 = q, bylz, cbylz; + for (j = 0; j < 4; j++) + repdis[j] = -1 - j; + bylz = cbylz = 0; + if (outsiz) { + if (tek_getnum_s7s(&s7ptr)) + return 1; + do { + j = 0; + do { + j++; + if (j >= 17) { + j += tek_getnum_s7s(&s7ptr); + break; + } + if (cbylz == 0) { + cbylz = 8; + bylz = *s7ptr++; + } + cbylz--; + i = bylz & 1; + bylz >>= 1; + } while (i == 0); + do { + *q++ = *s7ptr++; + } while (--j); + if (q >= q1) + break; + + j = 0; + do { + j++; + if (j >= 17) { + j += tek_getnum_s7s(&s7ptr); + break; + } + if (cbylz == 0) { + cbylz = 8; + bylz = *s7ptr++; + } + cbylz--; + i = bylz & 1; + bylz >>= 1; + } while (i == 0); + do { + i = *s7ptr++; + cp = i >> 4; + i &= 0x0f; + if ((i & 1) == 0) + i |= (tek_getnum_s7(&s7ptr) + 1) << 4; + i >>= 1; + ds = ~(i - 6); + if (i < 4) + ds = repdis[i]; + if (i == 4) + ds = repdis[0] - tek_getnum_s7(&s7ptr) - 1; + if (i == 5) + ds = repdis[0] + tek_getnum_s7(&s7ptr) + 1; + if (cp == 0) + cp = tek_getnum_s7(&s7ptr) + 16; + cp++; + if (i > 0) { + if (i > 1) { + if (i > 2) + repdis[3] = repdis[2]; + repdis[2] = repdis[1]; + } + repdis[1] = repdis[0]; + repdis[0] = ds; + } + if (q + ds < q0) + goto err; + if (q + cp > q1) + cp = q1 - q; + do { + *q = *(q + ds); + q++; + } while (--cp); + } while (--j); + } while (q < q1); + } + return 0; +err: + return 1; +} + +static int tek_decode2(int siz, UCHAR *p, UCHAR *q) +{ + UCHAR *p1 = p + siz; + int dsiz, hed, bsiz, st = 0; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (dsiz > bsiz || (hed & 0x21) != 0x01) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + st = tek_lzrestore_stk2(p1 - p, p, dsiz, q); + } + return st; +} + +static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int pb, int lp, int flags); + +static int tek_lzrestore_tek5(int srcsiz, UCHAR *src, int outsiz, UCHAR *outbuf) +{ + int wrksiz, lc, lp, pb, flags, *work, prop0, fl; + + if ((fl = (prop0 = *src) & 0x0f) == 0x01) /* 0001 */ + flags |= -1; + else if (fl == 0x05) + flags = -2; + else if (fl == 0x09) + flags &= 0; + else + return 1; + src++; + prop0 >>= 4; + if (prop0 == 0) + prop0 = *src++; + else { + static UCHAR prop0_table[] = { 0x5d, 0x00 }, prop1_table[] = { 0x00 }; + if (flags == -1) { + if (prop0 >= 3) + return 1; + prop0 = prop0_table[prop0 - 1]; + } else { + if (prop0 >= 2) + return 1; + prop0 = prop1_table[prop0 - 1]; + } + } + lp = prop0 / (9 * 5); + prop0 %= 9 * 5; + pb = prop0 / 9; + lc = prop0 % 9; + if (flags == 0) /* tek5:z2 */ + flags = *src++; + if (flags == -1) { /* stk5 */ + wrksiz = lp; + lp = pb; + pb = wrksiz; + } + wrksiz = 0x180 * sizeof (UINT32) + (0x840 + (0x300 << (lc + lp))) * sizeof (tek_TPRB); /* Å’á15KB, lc+lp=3‚È‚çA36KB */ + work = (int *) memman_alloc_4k((struct MEMMAN *) MEMMAN_ADDR, wrksiz); + if (work == NULL) + return -1; + flags = tek_decmain5(work, src, outsiz, outbuf, lc, pb, lp, flags); + memman_free_4k((struct MEMMAN *) MEMMAN_ADDR, (int) work, wrksiz); + return flags; +} + +struct tek_STR_BITMODEL { + UCHAR t, m, s, dmy; + UINT32 prb0, prb1, tmsk, ntm, lt, lt0, dmy4; +}; + +struct tek_STR_PRB { + struct tek_STR_PRB_PB { + struct tek_STR_PRB_PBST { + tek_TPRB mch, rep0l1; + } st[12]; + tek_TPRB lenlow[2][8], lenmid[2][8]; + } pb[16]; + struct tek_STR_PRB_ST { + tek_TPRB rep, repg0, repg1, repg2; + } st[12]; + tek_TPRB lensel[2][2], lenhigh[2][256], pslot[4][64], algn[64]; + tek_TPRB spdis[2][2+4+8+16+32], lenext[2+4+8+16+32]; + tek_TPRB repg3, fchgprm[2 * 32], tbmt[16], tbmm[16], fchglt; + tek_TPRB lit[1]; +}; + +struct tek_STR_RNGDEC { + UCHAR *p; + UINT32 range, code, rmsk; + jmp_buf errjmp; + struct tek_STR_BITMODEL bm[32], *ptbm[16]; + struct tek_STR_PRB probs; +}; + +static void tek_setbm5(struct tek_STR_BITMODEL *bm, int t, int m) +{ + bm->t = t; + bm->m = m; + bm->prb1 = -1 << (m + t); + bm->prb0 = ~bm->prb1; + bm->prb1 |= 1 << t; + bm->tmsk = (-1 << t) & 0xffff; + bm->prb0 &= bm->tmsk; + bm->prb1 &= bm->tmsk; + bm->ntm = ~bm->tmsk; + return; +} + +static int tek_rdget0(struct tek_STR_RNGDEC *rd, int n, int i) +{ + do { + while (rd->range < (UINT32) (1 << 24)) { + rd->range <<= 8; + rd->code = rd->code << 8 | *rd->p++; + } + rd->range >>= 1; + i += i; + if (rd->code >= rd->range) { + rd->code -= rd->range; + i |= 1; + } + } while (--n); + return ~i; +} + +static int tek_rdget1(struct tek_STR_RNGDEC *rd, tek_TPRB *prob0, int n, int j, struct tek_STR_BITMODEL *bm) +{ + UINT32 p, i, *prob, nm = n >> 4; + n &= 0x0f; + prob0 -= j; + do { + p = *(prob = prob0 + j); + if (bm->lt > 0) { + if (--bm->lt == 0) { + if (tek_rdget1(rd, &rd->probs.fchglt, 0x71, 0, &rd->bm[3]) == 0) { +err: + longjmp(rd->errjmp, 1); + } + i = bm - rd->bm; + if ((bm->s = tek_rdget1(rd, &rd->probs.fchgprm[i * 2 + bm->s], 0x71, 0, &rd->bm[1])) == 0) { + i = tek_rdget1(rd, rd->probs.tbmt, 0x74, 1, &rd->bm[2]) & 15; + if (i == 15) + goto err; + tek_setbm5(bm, i, ((tek_rdget1(rd, rd->probs.tbmm, 0x74, 1, &rd->bm[2]) - 1) & 15) + 1); + } + bm->lt = bm->lt0; + } + if (p < bm->prb0) { + p = bm->prb0; + goto fixprob; + } + if (p > bm->prb1) { + p = bm->prb1; + goto fixprob; + } + if (p & bm->ntm) { + p &= bm->tmsk; + fixprob: + *prob = p; + } + } + + while (rd->range < (UINT32) (1 << 24)) { + rd->range <<= 8; + rd->code = rd->code << 8 | *rd->p++; + } + j += j; + i = ((unsigned long long) (rd->range & rd->rmsk) * p) >> 16; + if (rd->code < i) { + j |= 1; + rd->range = i; + *prob += ((0x10000 - p) >> bm->m) & bm->tmsk; + } else { + rd->range -= i; + rd->code -= i; + *prob -= (p >> bm->m) & bm->tmsk; + } + --n; + if ((n & nm) == 0) + bm++; + } while (n); + return j; +} + +static UINT32 tek_revbit(UINT32 data, int len) +{ + UINT32 rev = 0; + do { + rev += rev + (data & 1); + data >>= 1; + } while (--len); + return rev; +} + +static int tek_getlen5(struct tek_STR_RNGDEC *rd, int m, int s_pos, int stk) +{ + int i; + if (tek_rdget1(rd, &rd->probs.lensel[m][0], 0x71, 0, rd->ptbm[3]) ^ stk) /* low */ + i = tek_rdget1(rd, rd->probs.pb[s_pos].lenlow[m], 0x73, 1, rd->ptbm[4]) & 7; + else if (tek_rdget1(rd, &rd->probs.lensel[m][1], 0x71, 0, rd->ptbm[3]) ^ stk) /* mid */ + i = tek_rdget1(rd, rd->probs.pb[s_pos].lenmid[m], 0x73, 1, rd->ptbm[5]); + else { + /* high */ + i = tek_rdget1(rd, rd->probs.lenhigh[m], 0x78, 1, rd->ptbm[6]) - (256 + 256 - 8); + if (i > 0) { + if (i < 6 && stk == 0) + i = tek_rdget1(rd, &rd->probs.lenext[(1 << i) - 2], i | 0x70, 1, rd->ptbm[7]) - 1; + else + i = tek_rdget0(rd, i, ~1) - 1; + i = tek_rdget0(rd, i, ~1) - 1; + } + i += 256 - 8 + 16; + } + return i; +} + +static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int pb, int lp, int flags) +{ + static int state_table[] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 }; + int i, j, k, pmch, rep[4], s, pos, m_pos = (1 << pb) - 1, m_lp = (1 << lp) - 1; + int stk = (flags == -1), lcr = 8 - lc, s_pos, lit0cntmsk = 0x78; + UINT32 *lit1; + struct tek_STR_RNGDEC *rd = (struct tek_STR_RNGDEC *) work; + struct tek_STR_PRB *prb = &rd->probs; + + rd->p = &src[4]; + rd->range |= -1; + rd->code = src[0] << 24 | src[1] << 16 | src[2] << 8 | src[3]; + for (i = 0; i < 4; i++) + rep[i] = ~i; + if (setjmp(rd->errjmp)) + goto err; + for (i = sizeof (struct tek_STR_PRB) / sizeof (tek_TPRB) + (0x300 << (lc + lp)) - 2; i >= 0; i--) + ((tek_TPRB *) prb)[i] = 1 << 15; + for (i = 0; i < 32; i++) { + rd->bm[i].lt = (i >= 4); + rd->bm[i].lt0 = (i < 24) ? 16 * 1024 : 8 * 1024; + rd->bm[i].s &= 0; + rd->bm[i].t = rd->bm[i].m = 5; + } + lit1 = prb->lit + ((256 << (lc + lp)) - 2); + if (stk) { + rd->rmsk = -1 << 11; + for (i = 0; i < 32; i++) + rd->bm[i].lt = 0; + for (i = 0; i < 14; i++) + rd->ptbm[i] = &rd->bm[0]; + } else { + UCHAR pt[14]; + static UCHAR pt1[14] = { + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 18, 18, 18, 8 + }; + static UCHAR pt2[14] = { + 8, 8, 10, 11, 12, 12, 14, 15, + 16, 16, 18, 18, 20, 21 + }; + /* + 0- 7:mch, mch, lit1, lensel, lenlow, lenmid, lenhigh, lenext + 8-15:pslot, pslot, sdis, sdis, align, rep-repg2 + */ + rd->rmsk |= -1; + rd->bm[1].t = 5; rd->bm[1].m = 3; /* for fchgprm */ + rd->bm[2].t = 9; rd->bm[2].m = 2; /* for tbmt, tbmm */ + if (flags & 0x40) { /* lt-flag */ + rd->bm[3].t = 0; rd->bm[3].m = 1; + prb->fchglt = 0xffff; + } + rd->bm[22].t = 0; rd->bm[22].m = 1; + prb->repg3 = 0xffff; + if (flags == -2) { /* z1 */ + rd->bm[22].lt = 0; + for (i = 0; i < 14; i++) + pt[i] = pt1[i]; + } else { + for (i = 0; i < 14; i++) + pt[i] = pt2[i]; + lit0cntmsk = (7 >> (flags & 3)) << 4 | 8; + pt[ 1] = 8 + ((flags & 0x04) != 0); /* mch */ + pt[ 5] = 12 + ((flags & 0x08) != 0); /* llm */ + pt[ 9] = 16 + ((flags & 0x10) != 0); /* pst */ + pt[11] = 18 + ((flags & 0x20) != 0); /* sds */ + } + for (i = 0; i < 14; i++) + rd->ptbm[i] = &rd->bm[pt[i]]; + } + for (i = 0; i < 32; i++) + tek_setbm5(&rd->bm[i], rd->bm[i].t, rd->bm[i].m); + + if ((tek_rdget1(rd, &prb->pb[0].st[0].mch, 0x71, 0, rd->ptbm[0]) ^ stk) == 0) + goto err; + *q++ = tek_rdget1(rd, prb->lit, lit0cntmsk, 1, &rd->bm[24]) & 0xff; + pmch &= 0; s &= 0; pos = 1; + while (pos < osiz) { + s_pos = pos & m_pos; + if (tek_rdget1(rd, &prb->pb[s_pos].st[s].mch, 0x71, 0, rd->ptbm[s > 0]) ^ stk) { + i = (q[-1] >> lcr | (pos & m_lp) << lc) << 8; + s = state_table[s]; + if (pmch == 0) + *q = tek_rdget1(rd, &prb->lit[i], lit0cntmsk, 1, &rd->bm[24]) & 0xff; + else { + struct tek_STR_BITMODEL *bm = &rd->bm[24]; + j = 1; + k = 8; + pmch = q[rep[0]]; + do { + j += j + tek_rdget1(rd, &lit1[(i + j) << 1 | pmch >> 7], 0x71, 0, rd->ptbm[2]); + k--; + if ((k & (lit0cntmsk >> 4)) == 0) + bm++; + if ((((pmch >> 7) ^ j) & 1) != 0 && k != 0) { + j = tek_rdget1(rd, &prb->lit[i + j - 1], k | (lit0cntmsk & 0x70), j, bm); + break; + } + pmch <<= 1; + } while (k); + *q = j & 0xff; + pmch &= 0; + } + pos++; + q++; + } else { /* lz */ + pmch |= 1; + if (tek_rdget1(rd, &prb->st[s].rep, 0x71, 0, rd->ptbm[13]) ^ stk) { /* len/dis */ + rep[3] = rep[2]; + rep[2] = rep[1]; + rep[1] = rep[0]; + j = i = tek_getlen5(rd, 0, s_pos, stk); + s = s < 7 ? 7 : 10; + if (j >= 4) + j = 3; + rep[0] = j = tek_rdget1(rd, prb->pslot[j], 0x76, 1, rd->ptbm[8 + (j == 3)]) & 0x3f; + if (j >= 4) { + k = (j >> 1) - 1; /* k = [1, 30] */ + rep[0] = (2 | (j & 1)) << k; + if (j < 14) /* k < 6 */ + rep[0] |= tek_revbit(tek_rdget1(rd, &prb->spdis[j & 1][(1 << k) - 2], k | 0x70, 1, rd->ptbm[10 + (k >= 4)]), k); + else { + if (stk == 0) { + if (k -= 6) + rep[0] |= tek_rdget0(rd, k, ~0) << 6; + rep[0] |= tek_revbit(tek_rdget1(rd, prb->algn, 0x76, 1, rd->ptbm[12]), 6); + } else { + rep[0] |= tek_rdget0(rd, k - 4, ~0) << 4; + rep[0] |= tek_revbit(tek_rdget1(rd, prb->algn, 0x74, 1, rd->ptbm[12]), 4); + } + } + } + rep[0] = ~rep[0]; + } else { /* repeat-dis */ + if (tek_rdget1(rd, &prb->st[s].repg0, 0x71, 0, rd->ptbm[13]) ^ stk) { /* rep0 */ + i |= -1; + if (tek_rdget1(rd, &prb->pb[s_pos].st[s].rep0l1, 0x71, 0, rd->ptbm[13]) == 0) { + s = s < 7 ? 9 : 11; + goto skip; + } + } else { + if (tek_rdget1(rd, &prb->st[s].repg1, 0x71, 0, rd->ptbm[13]) ^ stk) /* rep1 */ + i = rep[1]; + else { + if (tek_rdget1(rd, &prb->st[s].repg2, 0x71, 0, rd->ptbm[13]) ^ stk) /* rep2 */ + i = rep[2]; + else { + if (stk == 0) { + if (tek_rdget1(rd, &prb->repg3, 0x71, 0, &rd->bm[22]) == 0) + goto err; + } + i = rep[3]; /* rep3 */ + rep[3] = rep[2]; + } + rep[2] = rep[1]; + } + rep[1] = rep[0]; + rep[0] = i; + } + i = tek_getlen5(rd, 1, s_pos, stk); + s = s < 7 ? 8 : 11; + } +skip: + i += 2; + if (pos + rep[0] < 0) + goto err; + if (pos + i > osiz) + i = osiz - pos; + pos += i; + do { + *q = q[rep[0]]; + q++; + } while (--i); + } + } + return 0; +err: + return 1; +} + +static int tek_decode5(int siz, UCHAR *p, UCHAR *q) +{ + UCHAR *p1 = p + siz; + int dsiz, hed, bsiz, st = 0; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + if ((hed & 1) == 0) + st = tek_lzrestore_tek5(p1 - p + 1, p - 1, dsiz, q); + else { + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (hed & 0x20) + return 1; + if (bsiz == 256) + st = tek_lzrestore_tek5(p1 - p, p, dsiz, q); + else { + if (dsiz > bsiz) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + st = tek_lzrestore_tek5(p1 - p, p, dsiz, q); + } + } + } + return st; +} diff --git a/29_day/hello4/Makefile b/29_day/hello4/Makefile index f4cb8d2..557a184 100644 --- a/29_day/hello4/Makefile +++ b/29_day/hello4/Makefile @@ -3,3 +3,6 @@ STACK = 1k MALLOC = 0k include ../app_make.txt + +$(APP).hrb : $(APP).org Makefile + $(COPY) $(APP).org $(APP).hrb diff --git a/29_day/hello5/Makefile b/29_day/hello5/Makefile index 366ff9d..e07f802 100644 --- a/29_day/hello5/Makefile +++ b/29_day/hello5/Makefile @@ -3,3 +3,6 @@ STACK = 1k MALLOC = 0k include ../app_make.txt + +$(APP).hrb : $(APP).org Makefile + $(COPY) $(APP).org $(APP).hrb diff --git a/29_day/nihongo/nihongo.fnt b/29_day/nihongo/nihongo.fnt index e312bf5b7e4044adcff849980606951ba48bdd9a..4faa31d9f01099ff14153f17f7a8cfb891e15ab9 100644 GIT binary patch literal 58009 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 C0E|lj literal 145472 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

    GyQ$xxyMzR=Bd_b{buLbR zHTWajNXUo#w2S9EP!6j{6Deec(T~M1G8yQdG8wB)?Ck6#eyYzn;+lq&tqs)QntsUN z-ge#B9^pK1UF?^(ndy_0r1`}A(&R5CUX4{xzM6<%eQf%J%itgVjqrXvPkK8HEMoae zmv6q_A-Si3&#ovBQYj+&<;*MD>2E0H?8J(AiY?4;?my>AIsF&PwG!mXkdHiDI59DK zd~9s|_{0A2F^B#_YH;9PEs;XN^GUwxDO!C~j`}8==1x%@xDsFf_GY_ zI+0%>>NP-nZKWdqgzkyd(Dus6Qy=;bub21cxX&M8Zn;cG?$xo$1oaXep@DDpB94dt z-IjXP8QQjO2l%4=g&zD5t};D5$um+`ae%N1AEY6`ac!Me`N_?E3>{p$m|0rm)KSc&sVSy95$k>NxTg8 zDTyPMOZVna2cOH9LGS%4d71cSdt1pnxR)r=-h&?UlB)ARmCKjUpFjTttKY$Z>bC@{ z{=y0DWBf-DXy>YHi~{>$<2>$pI%zmH%Z~b)OOC2&P393DV6vkEVrWdcC2EYFn@L|g#?bBd63^fYW8H2;9EC$yFl?&MQRoxknSmaVEUviybU zCEYywQn`i~75_iuL%r|U?`ZP?`C(O6V6UfZ>Gcd`3_z*xA@e+6@1G59g2;K0|4LO% z`^3Yulkr3=PTF1cZ6vrX`ad1ee<9uA=2OlNZql0SDQNvE&ybPG8)O0ea~qBckcUpw z-GO~oUHRyjE7h>SYc5X)n+@;;19WJg$PG3I2!Bon`!8Gmxa_z3{e%2bXFhxPU{>j; zeP4SL{c3U1J+(Og(IIDSj0QqhUz}HZ%`+t6s6P?5HLTuWc7BnS&s^0m z1hQYz3cHEF?!7zMzt;2SgVf3T`5^xS?U4fIy)a12zlaTe(y0RFBKiUS{k)`N$flps zyqEobqF{d@KjE*XAiPKsM-%bsuz3uRuDLg$2N2Mb3p3fV<0k<(H1YPOORtmtm3s3c z_{UeEDzMxV;6=ai^}vAyV3|J#vtFp-y@%$)coQhjyj0)7cTjH*9hgSNMa8JgANYTM zaqXTfjK6)pt^M$Uho*PZBPz!8-k+ShHa+$Jz~ql7Cg6wi@2UP*`B(H0M{HYg;NPjX z4(0FB-w*kMMQP>7KJ-n}6MKYT`0%X{-@5RM=I5oM(3p%P4u&4Bl$nH?Pi6GQEYwef zKkM)JZ3q3!?hkW{xt}&L{@h4cqike;xE}Y?(mHfwNP>QE0Mfl1TD}vFLcf(N6^^yJ z7Y5%6;(w(?N%nhE1?YUuyX?Ik9rA{fWH6z`qCdn4E>T^k{=m;foYcyq{CD>1>FK^1 zzTN4;Ii{oVW)R=JsP*B{C<67#*96NoJ`;?!`gE7%)`GFu%!vZ_FP~R`i+KtC99Dlf z7G=J%$&C-rO8xw_c!c3)T6;impa4={f#-Ns2mdP*hC?^gbb(pR45!Rw9l zjoL#E@vssHUx}|piC;t_mWZ_>KkNF7+l*s(U>4$z%LJzXx$!Tb6z1i#??tUYGNND3 zClM|WKv@cpBA>W_k?6=_4OA5_wtoYhO=&{r-&N)!ibWTYl&y~aq4adco4v*WzzuvvE!ZZCPZshuUwgyuJX2YG z-29jHVeL4$PyTHVu3yWLH!uB12kVg<>N#%MMFnQwNtD{sqvx=&z_Dsd`YT$OwBs$B zJmbeCW(%4pUHA9gj`8P$5D$|JTrhUtvLgr%)X@LZ8S+;*>f4>qR#!g*WHk@9LH&Ua zlX`Mf|0V7j*?m12UQ+r4{wJA#>0YOV6vKZ&`~>qa@y~MY7cWCU`a-5BM-%1#k$k}a zvETlj{avt01N`&3#G!-xr)Gp-?EmG7JAI6P^`m9wPs=|*eNz+lP2^AdoUbjt*o=;d zniPqce~R9ENA`S+1v(Pg|F>LEeM4X0A(9`DkSITPYV-b6A6fn`3xqnIzmMN}p$p_u zF2BU?Z)$%B{hE40lHd{8qZ$aC`oj1=hCME?VXy&zfWNi#2{BaU{SbOW(7%NL27!N}kJRR@wM7Xmf5uS=Fek=YHT`DBvNxu@UfWdUHa+}OXvHZ(& zb^jH_jt~Ih!t=$Sqo!oLEi3@nr@r(oh~s|I)5ZCa@5^^-{x{!?{qXxzQ!30+*GCd9 zop|5XT~z+Ls-Ir#{G1AvpS-|%bV4SG=3)O^|0q}o3WN^U-zn~tU8Q4Z8vKU9IkBd* z>z3bvT!sD9eIvW)DEaBoKf@2oixVsIFW^Az$NZv3@4jI^v$FXr=GS_@w*7`Ai${c| zf3T15p~>LEdam8J$Y;Oe|BEpE%I9xKZkyx8+><#aR1S81J#Fu^9%*%%ux;c z@9_Be%&aaC@?#kjcuVhJy8lL`KQi=a&SEqSk^F6j&K&?ECdeKy9RH^JY~x2k$HY@1 zrl$8__YZEb?!vl1=UaKUDySB;{)~^>!KK8d{F3!Y_Q;$gRawWEnz`oBn{fZZ=vJ-= zK6a?U2Kbx(g=!MiSLpe(6yR|fd}M#HL9_&v-f8@hP;|S}0K|b9KP2RJ)Eckm^H&wW zZ;x@UAhaNC7H0u^t4~Y3!2bjvOc=LgcVEG!zD4kH9?4fOC5eAN_iL_ijZ^%g0W4_w zfE&@{TH~kO($w zNfx1K^>aL=oe41f>5}RjfE=p5Fo1n1)?N7;lY<+ z!X^HN{=xh;)URT! /* NULL */ +#include /* malloc, free */ +#include + +typedef unsigned char UCHAR; +typedef unsigned int UINT32; +typedef UINT32 tek_TPRB; + +static int tek_decode1(int siz, UCHAR *p, UCHAR *q); +static int tek_decode2(int siz, UCHAR *p, UCHAR *q); +static int tek_decode5(int siz, UCHAR *p, UCHAR *q); + +static unsigned int tek_getnum_s7s(UCHAR **pp) +{ + unsigned int s = 0; + UCHAR *p = *pp; + do { + s = s << 7 | *p++; + } while ((s & 1) == 0); + s >>= 1; + *pp = p; + return s; +} + +int autodecomp(int siz0, UCHAR *p0, int siz) +{ + unsigned char *b = p0, *c, *c0; + int s, i, e = 0; + if ((*(int *) &b[0x08] == 0x5341534f) && (*(int *) &b[0x0c] == 0x504d434b)) { + if (*(int *) &b[0x04] == 0x00000001) { + unsigned int t = *(int *) &b[0x00]; + e |= 1; + if (0xffffff83 <= t && t <= 0xffffff89) { + c = &b[0x10]; + s = tek_getnum_s7s(&c); + if (s + siz - 0x10 <= siz0) { + c0 = c = b + siz0 - siz; + for (i = siz - 1; i >= 0x10; i--) + c[i] = b[i]; + c += 0x10; + tek_getnum_s7s(&c); + if (t == 0xffffff83) + e = tek_decode1(siz, c0, b); + if (t == 0xffffff85) + e = tek_decode2(siz, c0, b); + if (t == 0xffffff89) + e = tek_decode5(siz, c0, b); + siz = s; + } + } + } + } + if (e) + siz |= -1; + return siz; +} + +static int tek_lzrestore_stk1(int srcsiz, UCHAR *src, int outsiz, UCHAR *q) +{ + int by, lz, cp, ds; + UCHAR *q1 = q + outsiz, *s7ptr = src, *q0 = q; + do { + if ((by = (lz = *s7ptr++) & 0x0f) == 0) + by = tek_getnum_s7s(&s7ptr); + if ((lz >>= 4) == 0) + lz = tek_getnum_s7s(&s7ptr); + do { + *q++ = *s7ptr++; + } while (--by); + if (q >= q1) + break; + do { + ds = (cp = *s7ptr++) & 0x0f; + if ((ds & 1) == 0) { + do { + ds = ds << 7 | *s7ptr++; + } while ((ds & 1) == 0); + } + ds = ~(ds >> 1); + if ((cp >>= 4) == 0) { + do { + cp = cp << 7 | *s7ptr++; + } while ((cp & 1) == 0); + cp >>= 1; + } + cp++; + if (q + ds < q0) + goto err; + if (q + cp > q1) + cp = q1 - q; + do { + *q = *(q + ds); + q++; + } while (--cp); + } while (--lz); + } while (q < q1); + return 0; +err: + return 1; +} + +static int tek_decode1(int siz, UCHAR *p, UCHAR *q) +{ + int dsiz, hed, bsiz; + UCHAR *p1 = p + siz; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (dsiz > bsiz || (hed & 0x21) != 0x01) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + if (tek_getnum_s7s(&p) != 0) + return 1; + return tek_lzrestore_stk1(p1 - p, p, dsiz, q); + } + return 0; +} + +static unsigned int tek_getnum_s7(UCHAR **pp) +{ + unsigned int s = 0, b = 0, a = 1; + UCHAR *p = *pp; + for (;;) { + s = s << 7 | *p++; + if (s & 1) + break; + a <<= 7; + b += a; + } + s >>= 1; + *pp = p; + return s + b; +} + +static int tek_lzrestore_stk2(int srcsiz, UCHAR *src, int outsiz, UCHAR *q) +{ + int cp, ds, repdis[4], i, j; + UCHAR *q1 = q + outsiz, *s7ptr = src, *q0 = q, bylz, cbylz; + for (j = 0; j < 4; j++) + repdis[j] = -1 - j; + bylz = cbylz = 0; + if (outsiz) { + if (tek_getnum_s7s(&s7ptr)) + return 1; + do { + j = 0; + do { + j++; + if (j >= 17) { + j += tek_getnum_s7s(&s7ptr); + break; + } + if (cbylz == 0) { + cbylz = 8; + bylz = *s7ptr++; + } + cbylz--; + i = bylz & 1; + bylz >>= 1; + } while (i == 0); + do { + *q++ = *s7ptr++; + } while (--j); + if (q >= q1) + break; + + j = 0; + do { + j++; + if (j >= 17) { + j += tek_getnum_s7s(&s7ptr); + break; + } + if (cbylz == 0) { + cbylz = 8; + bylz = *s7ptr++; + } + cbylz--; + i = bylz & 1; + bylz >>= 1; + } while (i == 0); + do { + i = *s7ptr++; + cp = i >> 4; + i &= 0x0f; + if ((i & 1) == 0) + i |= (tek_getnum_s7(&s7ptr) + 1) << 4; + i >>= 1; + ds = ~(i - 6); + if (i < 4) + ds = repdis[i]; + if (i == 4) + ds = repdis[0] - tek_getnum_s7(&s7ptr) - 1; + if (i == 5) + ds = repdis[0] + tek_getnum_s7(&s7ptr) + 1; + if (cp == 0) + cp = tek_getnum_s7(&s7ptr) + 16; + cp++; + if (i > 0) { + if (i > 1) { + if (i > 2) + repdis[3] = repdis[2]; + repdis[2] = repdis[1]; + } + repdis[1] = repdis[0]; + repdis[0] = ds; + } + if (q + ds < q0) + goto err; + if (q + cp > q1) + cp = q1 - q; + do { + *q = *(q + ds); + q++; + } while (--cp); + } while (--j); + } while (q < q1); + } + return 0; +err: + return 1; +} + +static int tek_decode2(int siz, UCHAR *p, UCHAR *q) +{ + UCHAR *p1 = p + siz; + int dsiz, hed, bsiz, st = 0; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (dsiz > bsiz || (hed & 0x21) != 0x01) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + st = tek_lzrestore_stk2(p1 - p, p, dsiz, q); + } + return st; +} + +static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int pb, int lp, int flags); + +static int tek_lzrestore_tek5(int srcsiz, UCHAR *src, int outsiz, UCHAR *outbuf) +{ + int wrksiz, lc, lp, pb, flags, *work, prop0, fl; + + if ((fl = (prop0 = *src) & 0x0f) == 0x01) /* 0001 */ + flags |= -1; + else if (fl == 0x05) + flags = -2; + else if (fl == 0x09) + flags &= 0; + else + return 1; + src++; + prop0 >>= 4; + if (prop0 == 0) + prop0 = *src++; + else { + static UCHAR prop0_table[] = { 0x5d, 0x00 }, prop1_table[] = { 0x00 }; + if (flags == -1) { + if (prop0 >= 3) + return 1; + prop0 = prop0_table[prop0 - 1]; + } else { + if (prop0 >= 2) + return 1; + prop0 = prop1_table[prop0 - 1]; + } + } + lp = prop0 / (9 * 5); + prop0 %= 9 * 5; + pb = prop0 / 9; + lc = prop0 % 9; + if (flags == 0) /* tek5:z2 */ + flags = *src++; + if (flags == -1) { /* stk5 */ + wrksiz = lp; + lp = pb; + pb = wrksiz; + } + wrksiz = 0x180 * sizeof (UINT32) + (0x840 + (0x300 << (lc + lp))) * sizeof (tek_TPRB); + work = malloc(wrksiz); + if (work == NULL) + return -1; + flags = tek_decmain5(work, src, outsiz, outbuf, lc, pb, lp, flags); + free(work); + return flags; +} + +struct tek_STR_BITMODEL { + UCHAR t, m, s, dmy; + UINT32 prb0, prb1, tmsk, ntm, lt, lt0, dmy4; +}; + +struct tek_STR_PRB { + struct tek_STR_PRB_PB { + struct tek_STR_PRB_PBST { + tek_TPRB mch, rep0l1; + } st[12]; + tek_TPRB lenlow[2][8], lenmid[2][8]; + } pb[16]; + struct tek_STR_PRB_ST { + tek_TPRB rep, repg0, repg1, repg2; + } st[12]; + tek_TPRB lensel[2][2], lenhigh[2][256], pslot[4][64], algn[64]; + tek_TPRB spdis[2][2+4+8+16+32], lenext[2+4+8+16+32]; + tek_TPRB repg3, fchgprm[2 * 32], tbmt[16], tbmm[16], fchglt; + tek_TPRB lit[1]; +}; + +struct tek_STR_RNGDEC { + UCHAR *p; + UINT32 range, code, rmsk; + jmp_buf errjmp; + struct tek_STR_BITMODEL bm[32], *ptbm[16]; + struct tek_STR_PRB probs; +}; + +static void tek_setbm5(struct tek_STR_BITMODEL *bm, int t, int m) +{ + bm->t = t; + bm->m = m; + bm->prb1 = -1 << (m + t); + bm->prb0 = ~bm->prb1; + bm->prb1 |= 1 << t; + bm->tmsk = (-1 << t) & 0xffff; + bm->prb0 &= bm->tmsk; + bm->prb1 &= bm->tmsk; + bm->ntm = ~bm->tmsk; + return; +} + +static int tek_rdget0(struct tek_STR_RNGDEC *rd, int n, int i) +{ + do { + while (rd->range < (UINT32) (1 << 24)) { + rd->range <<= 8; + rd->code = rd->code << 8 | *rd->p++; + } + rd->range >>= 1; + i += i; + if (rd->code >= rd->range) { + rd->code -= rd->range; + i |= 1; + } + } while (--n); + return ~i; +} + +static int tek_rdget1(struct tek_STR_RNGDEC *rd, tek_TPRB *prob0, int n, int j, struct tek_STR_BITMODEL *bm) +{ + UINT32 p, i, *prob, nm = n >> 4; + n &= 0x0f; + prob0 -= j; + do { + p = *(prob = prob0 + j); + if (bm->lt > 0) { + if (--bm->lt == 0) { + if (tek_rdget1(rd, &rd->probs.fchglt, 0x71, 0, &rd->bm[3]) == 0) { +err: + longjmp(rd->errjmp, 1); + } + i = bm - rd->bm; + if ((bm->s = tek_rdget1(rd, &rd->probs.fchgprm[i * 2 + bm->s], 0x71, 0, &rd->bm[1])) == 0) { + i = tek_rdget1(rd, rd->probs.tbmt, 0x74, 1, &rd->bm[2]) & 15; + if (i == 15) + goto err; + tek_setbm5(bm, i, ((tek_rdget1(rd, rd->probs.tbmm, 0x74, 1, &rd->bm[2]) - 1) & 15) + 1); + } + bm->lt = bm->lt0; + } + if (p < bm->prb0) { + p = bm->prb0; + goto fixprob; + } + if (p > bm->prb1) { + p = bm->prb1; + goto fixprob; + } + if (p & bm->ntm) { + p &= bm->tmsk; + fixprob: + *prob = p; + } + } + + while (rd->range < (UINT32) (1 << 24)) { + rd->range <<= 8; + rd->code = rd->code << 8 | *rd->p++; + } + j += j; + i = ((unsigned long long) (rd->range & rd->rmsk) * p) >> 16; + if (rd->code < i) { + j |= 1; + rd->range = i; + *prob += ((0x10000 - p) >> bm->m) & bm->tmsk; + } else { + rd->range -= i; + rd->code -= i; + *prob -= (p >> bm->m) & bm->tmsk; + } + --n; + if ((n & nm) == 0) + bm++; + } while (n); + return j; +} + +static UINT32 tek_revbit(UINT32 data, int len) +{ + UINT32 rev = 0; + do { + rev += rev + (data & 1); + data >>= 1; + } while (--len); + return rev; +} + +static int tek_getlen5(struct tek_STR_RNGDEC *rd, int m, int s_pos, int stk) +{ + int i; + if (tek_rdget1(rd, &rd->probs.lensel[m][0], 0x71, 0, rd->ptbm[3]) ^ stk) /* low */ + i = tek_rdget1(rd, rd->probs.pb[s_pos].lenlow[m], 0x73, 1, rd->ptbm[4]) & 7; + else if (tek_rdget1(rd, &rd->probs.lensel[m][1], 0x71, 0, rd->ptbm[3]) ^ stk) /* mid */ + i = tek_rdget1(rd, rd->probs.pb[s_pos].lenmid[m], 0x73, 1, rd->ptbm[5]); + else { + /* high */ + i = tek_rdget1(rd, rd->probs.lenhigh[m], 0x78, 1, rd->ptbm[6]) - (256 + 256 - 8); + if (i > 0) { + if (i < 6 && stk == 0) + i = tek_rdget1(rd, &rd->probs.lenext[(1 << i) - 2], i | 0x70, 1, rd->ptbm[7]) - 1; + else + i = tek_rdget0(rd, i, ~1) - 1; + i = tek_rdget0(rd, i, ~1) - 1; + } + i += 256 - 8 + 16; + } + return i; +} + +static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int pb, int lp, int flags) +{ + static int state_table[] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 }; + int i, j, k, pmch, rep[4], s, pos, m_pos = (1 << pb) - 1, m_lp = (1 << lp) - 1; + int stk = (flags == -1), lcr = 8 - lc, s_pos, lit0cntmsk = 0x78; + UINT32 *lit1; + struct tek_STR_RNGDEC *rd = (struct tek_STR_RNGDEC *) work; + struct tek_STR_PRB *prb = &rd->probs; + + rd->p = &src[4]; + rd->range |= -1; + rd->code = src[0] << 24 | src[1] << 16 | src[2] << 8 | src[3]; + for (i = 0; i < 4; i++) + rep[i] = ~i; + if (setjmp(rd->errjmp)) + goto err; + for (i = sizeof (struct tek_STR_PRB) / sizeof (tek_TPRB) + (0x300 << (lc + lp)) - 2; i >= 0; i--) + ((tek_TPRB *) prb)[i] = 1 << 15; + for (i = 0; i < 32; i++) { + rd->bm[i].lt = (i >= 4); + rd->bm[i].lt0 = (i < 24) ? 16 * 1024 : 8 * 1024; + rd->bm[i].s &= 0; + rd->bm[i].t = rd->bm[i].m = 5; + } + lit1 = prb->lit + ((256 << (lc + lp)) - 2); + if (stk) { + rd->rmsk = -1 << 11; + for (i = 0; i < 32; i++) + rd->bm[i].lt = 0; + for (i = 0; i < 14; i++) + rd->ptbm[i] = &rd->bm[0]; + } else { + UCHAR pt[14]; + static UCHAR pt1[14] = { + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 18, 18, 18, 8 + }; + static UCHAR pt2[14] = { + 8, 8, 10, 11, 12, 12, 14, 15, + 16, 16, 18, 18, 20, 21 + }; + /* + 0- 7:mch, mch, lit1, lensel, lenlow, lenmid, lenhigh, lenext + 8-15:pslot, pslot, sdis, sdis, align, rep-repg2 + */ + rd->rmsk |= -1; + rd->bm[1].t = 5; rd->bm[1].m = 3; /* for fchgprm */ + rd->bm[2].t = 9; rd->bm[2].m = 2; /* for tbmt, tbmm */ + if (flags & 0x40) { /* lt-flag */ + rd->bm[3].t = 0; rd->bm[3].m = 1; + prb->fchglt = 0xffff; + } + rd->bm[22].t = 0; rd->bm[22].m = 1; + prb->repg3 = 0xffff; + if (flags == -2) { /* z1 */ + rd->bm[22].lt = 0; + for (i = 0; i < 14; i++) + pt[i] = pt1[i]; + } else { + for (i = 0; i < 14; i++) + pt[i] = pt2[i]; + lit0cntmsk = (7 >> (flags & 3)) << 4 | 8; + pt[ 1] = 8 + ((flags & 0x04) != 0); /* mch */ + pt[ 5] = 12 + ((flags & 0x08) != 0); /* llm */ + pt[ 9] = 16 + ((flags & 0x10) != 0); /* pst */ + pt[11] = 18 + ((flags & 0x20) != 0); /* sds */ + } + for (i = 0; i < 14; i++) + rd->ptbm[i] = &rd->bm[pt[i]]; + } + for (i = 0; i < 32; i++) + tek_setbm5(&rd->bm[i], rd->bm[i].t, rd->bm[i].m); + + if ((tek_rdget1(rd, &prb->pb[0].st[0].mch, 0x71, 0, rd->ptbm[0]) ^ stk) == 0) + goto err; + *q++ = tek_rdget1(rd, prb->lit, lit0cntmsk, 1, &rd->bm[24]) & 0xff; + pmch &= 0; s &= 0; pos = 1; + while (pos < osiz) { + s_pos = pos & m_pos; + if (tek_rdget1(rd, &prb->pb[s_pos].st[s].mch, 0x71, 0, rd->ptbm[s > 0]) ^ stk) { + i = (q[-1] >> lcr | (pos & m_lp) << lc) << 8; + s = state_table[s]; + if (pmch == 0) + *q = tek_rdget1(rd, &prb->lit[i], lit0cntmsk, 1, &rd->bm[24]) & 0xff; + else { + struct tek_STR_BITMODEL *bm = &rd->bm[24]; + j = 1; /* lit1‚͍ŏ‰‚©‚ç2‚ðŒ¸‚¶‚Ä‚ ‚é */ + k = 8; + pmch = q[rep[0]]; + do { + j += j + tek_rdget1(rd, &lit1[(i + j) << 1 | pmch >> 7], 0x71, 0, rd->ptbm[2]); + k--; + if ((k & (lit0cntmsk >> 4)) == 0) + bm++; + if ((((pmch >> 7) ^ j) & 1) != 0 && k != 0) { + j = tek_rdget1(rd, &prb->lit[i + j - 1], k | (lit0cntmsk & 0x70), j, bm); + break; + } + pmch <<= 1; + } while (k); + *q = j & 0xff; + pmch &= 0; + } + pos++; + q++; + } else { /* lz */ + pmch |= 1; + if (tek_rdget1(rd, &prb->st[s].rep, 0x71, 0, rd->ptbm[13]) ^ stk) { /* len/dis */ + rep[3] = rep[2]; + rep[2] = rep[1]; + rep[1] = rep[0]; + j = i = tek_getlen5(rd, 0, s_pos, stk); + s = s < 7 ? 7 : 10; + if (j >= 4) + j = 3; + rep[0] = j = tek_rdget1(rd, prb->pslot[j], 0x76, 1, rd->ptbm[8 + (j == 3)]) & 0x3f; + if (j >= 4) { + k = (j >> 1) - 1; /* k = [1, 30] */ + rep[0] = (2 | (j & 1)) << k; + if (j < 14) /* k < 6 */ + rep[0] |= tek_revbit(tek_rdget1(rd, &prb->spdis[j & 1][(1 << k) - 2], k | 0x70, 1, rd->ptbm[10 + (k >= 4)]), k); + else { + if (stk == 0) { + if (k -= 6) + rep[0] |= tek_rdget0(rd, k, ~0) << 6; + rep[0] |= tek_revbit(tek_rdget1(rd, prb->algn, 0x76, 1, rd->ptbm[12]), 6); + } else { + rep[0] |= tek_rdget0(rd, k - 4, ~0) << 4; + rep[0] |= tek_revbit(tek_rdget1(rd, prb->algn, 0x74, 1, rd->ptbm[12]), 4); + } + } + } + rep[0] = ~rep[0]; + } else { /* repeat-dis */ + if (tek_rdget1(rd, &prb->st[s].repg0, 0x71, 0, rd->ptbm[13]) ^ stk) { /* rep0 */ + i |= -1; + if (tek_rdget1(rd, &prb->pb[s_pos].st[s].rep0l1, 0x71, 0, rd->ptbm[13]) == 0) { + s = s < 7 ? 9 : 11; + goto skip; + } + } else { + if (tek_rdget1(rd, &prb->st[s].repg1, 0x71, 0, rd->ptbm[13]) ^ stk) /* rep1 */ + i = rep[1]; + else { + if (tek_rdget1(rd, &prb->st[s].repg2, 0x71, 0, rd->ptbm[13]) ^ stk) /* rep2 */ + i = rep[2]; + else { + if (stk == 0) { + if (tek_rdget1(rd, &prb->repg3, 0x71, 0, &rd->bm[22]) == 0) + goto err; + } + i = rep[3]; /* rep3 */ + rep[3] = rep[2]; + } + rep[2] = rep[1]; + } + rep[1] = rep[0]; + rep[0] = i; + } + i = tek_getlen5(rd, 1, s_pos, stk); + s = s < 7 ? 8 : 11; + } +skip: + i += 2; + if (pos + rep[0] < 0) + goto err; + if (pos + i > osiz) + i = osiz - pos; + pos += i; + do { + *q = q[rep[0]]; + q++; + } while (--i); + } + } + return 0; +err: + return 1; +} + +int tek_decode5(int siz, UCHAR *p, UCHAR *q) +{ + UCHAR *p1 = p + siz; + int dsiz, hed, bsiz, st = 0; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + if ((hed & 1) == 0) + st = tek_lzrestore_tek5(p1 - p + 1, p - 1, dsiz, q); + else { + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (hed & 0x20) + return 1; + if (bsiz == 256) + st = tek_lzrestore_tek5(p1 - p, p, dsiz, q); + else { + if (dsiz > bsiz) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + st = tek_lzrestore_tek5(p1 - p, p, dsiz, q); + } + } + } + return st; +} diff --git a/29_day/tek/tek.c b/29_day/tek/tek.c new file mode 100644 index 0000000..4062dcc --- /dev/null +++ b/29_day/tek/tek.c @@ -0,0 +1,646 @@ +#include "bootpack.h" +#include +#include +#define NULL 0 + +typedef unsigned char UCHAR; +typedef unsigned int UINT32; +typedef UINT32 tek_TPRB; + +static int tek_decode1(int siz, UCHAR *p, UCHAR *q); +static int tek_decode2(int siz, UCHAR *p, UCHAR *q); +static int tek_decode5(int siz, UCHAR *p, UCHAR *q); + +static unsigned int tek_getnum_s7s(UCHAR **pp) +{ + unsigned int s = 0; + UCHAR *p = *pp; + do { + s = s << 7 | *p++; + } while ((s & 1) == 0); + s >>= 1; + *pp = p; + return s; +} + +int tek_getsize(unsigned char *p) +{ + static char header[15] = { + 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x41, 0x53, 0x4b, 0x43, 0x4d, 0x50 + }; + int size = -1; + if (memcmp(p + 1, header, 15) == 0 && (*p == 0x83 || *p == 0x85 || *p == 0x89)) { + p += 16; + size = tek_getnum_s7s(&p); + } + return size; +} /* (注)memcmp和strncmp差不多,这个函数忽略字符串中的0并一直比较到指定的15个字符为止*/ + +int tek_decomp(unsigned char *p, char *q, int size) +{ + int err = -1; + if (*p == 0x83) { + err = tek_decode1(size, p, q); + } else if (*p == 0x85) { + err = tek_decode2(size, p, q); + } else if (*p == 0x89) { + err = tek_decode5(size, p, q); + } + if (err != 0) { + return -1; /*失败*/ + } + return 0; /*成功*/ +} + +static int tek_lzrestore_stk1(int srcsiz, UCHAR *src, int outsiz, UCHAR *q) +{ + int by, lz, cp, ds; + UCHAR *q1 = q + outsiz, *s7ptr = src, *q0 = q; + do { + if ((by = (lz = *s7ptr++) & 0x0f) == 0) + by = tek_getnum_s7s(&s7ptr); + if ((lz >>= 4) == 0) + lz = tek_getnum_s7s(&s7ptr); + do { + *q++ = *s7ptr++; + } while (--by); + if (q >= q1) + break; + do { + ds = (cp = *s7ptr++) & 0x0f; + if ((ds & 1) == 0) { + do { + ds = ds << 7 | *s7ptr++; + } while ((ds & 1) == 0); + } + ds = ~(ds >> 1); + if ((cp >>= 4) == 0) { + do { + cp = cp << 7 | *s7ptr++; + } while ((cp & 1) == 0); + cp >>= 1; + } + cp++; + if (q + ds < q0) + goto err; + if (q + cp > q1) + cp = q1 - q; + do { + *q = *(q + ds); + q++; + } while (--cp); + } while (--lz); + } while (q < q1); + return 0; +err: + return 1; +} + +static int tek_decode1(int siz, UCHAR *p, UCHAR *q) +{ + int dsiz, hed, bsiz; + UCHAR *p1 = p + siz; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (dsiz > bsiz || (hed & 0x21) != 0x01) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + if (tek_getnum_s7s(&p) != 0) + return 1; + return tek_lzrestore_stk1(p1 - p, p, dsiz, q); + } + return 0; +} + +static unsigned int tek_getnum_s7(UCHAR **pp) +{ + unsigned int s = 0, b = 0, a = 1; + UCHAR *p = *pp; + for (;;) { + s = s << 7 | *p++; + if (s & 1) + break; + a <<= 7; + b += a; + } + s >>= 1; + *pp = p; + return s + b; +} + +static int tek_lzrestore_stk2(int srcsiz, UCHAR *src, int outsiz, UCHAR *q) +{ + int cp, ds, repdis[4], i, j; + UCHAR *q1 = q + outsiz, *s7ptr = src, *q0 = q, bylz, cbylz; + for (j = 0; j < 4; j++) + repdis[j] = -1 - j; + bylz = cbylz = 0; + if (outsiz) { + if (tek_getnum_s7s(&s7ptr)) + return 1; + do { + j = 0; + do { + j++; + if (j >= 17) { + j += tek_getnum_s7s(&s7ptr); + break; + } + if (cbylz == 0) { + cbylz = 8; + bylz = *s7ptr++; + } + cbylz--; + i = bylz & 1; + bylz >>= 1; + } while (i == 0); + do { + *q++ = *s7ptr++; + } while (--j); + if (q >= q1) + break; + + j = 0; + do { + j++; + if (j >= 17) { + j += tek_getnum_s7s(&s7ptr); + break; + } + if (cbylz == 0) { + cbylz = 8; + bylz = *s7ptr++; + } + cbylz--; + i = bylz & 1; + bylz >>= 1; + } while (i == 0); + do { + i = *s7ptr++; + cp = i >> 4; + i &= 0x0f; + if ((i & 1) == 0) + i |= (tek_getnum_s7(&s7ptr) + 1) << 4; + i >>= 1; + ds = ~(i - 6); + if (i < 4) + ds = repdis[i]; + if (i == 4) + ds = repdis[0] - tek_getnum_s7(&s7ptr) - 1; + if (i == 5) + ds = repdis[0] + tek_getnum_s7(&s7ptr) + 1; + if (cp == 0) + cp = tek_getnum_s7(&s7ptr) + 16; + cp++; + if (i > 0) { + if (i > 1) { + if (i > 2) + repdis[3] = repdis[2]; + repdis[2] = repdis[1]; + } + repdis[1] = repdis[0]; + repdis[0] = ds; + } + if (q + ds < q0) + goto err; + if (q + cp > q1) + cp = q1 - q; + do { + *q = *(q + ds); + q++; + } while (--cp); + } while (--j); + } while (q < q1); + } + return 0; +err: + return 1; +} + +static int tek_decode2(int siz, UCHAR *p, UCHAR *q) +{ + UCHAR *p1 = p + siz; + int dsiz, hed, bsiz, st = 0; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (dsiz > bsiz || (hed & 0x21) != 0x01) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + st = tek_lzrestore_stk2(p1 - p, p, dsiz, q); + } + return st; +} + +static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int pb, int lp, int flags); + +static int tek_lzrestore_tek5(int srcsiz, UCHAR *src, int outsiz, UCHAR *outbuf) +{ + int wrksiz, lc, lp, pb, flags, *work, prop0, fl; + + if ((fl = (prop0 = *src) & 0x0f) == 0x01) /* 0001 */ + flags |= -1; + else if (fl == 0x05) + flags = -2; + else if (fl == 0x09) + flags &= 0; + else + return 1; + src++; + prop0 >>= 4; + if (prop0 == 0) + prop0 = *src++; + else { + static UCHAR prop0_table[] = { 0x5d, 0x00 }, prop1_table[] = { 0x00 }; + if (flags == -1) { + if (prop0 >= 3) + return 1; + prop0 = prop0_table[prop0 - 1]; + } else { + if (prop0 >= 2) + return 1; + prop0 = prop1_table[prop0 - 1]; + } + } + lp = prop0 / (9 * 5); + prop0 %= 9 * 5; + pb = prop0 / 9; + lc = prop0 % 9; + if (flags == 0) /* tek5:z2 */ + flags = *src++; + if (flags == -1) { /* stk5 */ + wrksiz = lp; + lp = pb; + pb = wrksiz; + } + wrksiz = 0x180 * sizeof (UINT32) + (0x840 + (0x300 << (lc + lp))) * sizeof (tek_TPRB); /* Å’á15KB, lc+lp=3‚È‚çA36KB */ + work = (int *) memman_alloc_4k((struct MEMMAN *) MEMMAN_ADDR, wrksiz); + if (work == NULL) + return -1; + flags = tek_decmain5(work, src, outsiz, outbuf, lc, pb, lp, flags); + memman_free_4k((struct MEMMAN *) MEMMAN_ADDR, (int) work, wrksiz); + return flags; +} + +struct tek_STR_BITMODEL { + UCHAR t, m, s, dmy; + UINT32 prb0, prb1, tmsk, ntm, lt, lt0, dmy4; +}; + +struct tek_STR_PRB { + struct tek_STR_PRB_PB { + struct tek_STR_PRB_PBST { + tek_TPRB mch, rep0l1; + } st[12]; + tek_TPRB lenlow[2][8], lenmid[2][8]; + } pb[16]; + struct tek_STR_PRB_ST { + tek_TPRB rep, repg0, repg1, repg2; + } st[12]; + tek_TPRB lensel[2][2], lenhigh[2][256], pslot[4][64], algn[64]; + tek_TPRB spdis[2][2+4+8+16+32], lenext[2+4+8+16+32]; + tek_TPRB repg3, fchgprm[2 * 32], tbmt[16], tbmm[16], fchglt; + tek_TPRB lit[1]; +}; + +struct tek_STR_RNGDEC { + UCHAR *p; + UINT32 range, code, rmsk; + jmp_buf errjmp; + struct tek_STR_BITMODEL bm[32], *ptbm[16]; + struct tek_STR_PRB probs; +}; + +static void tek_setbm5(struct tek_STR_BITMODEL *bm, int t, int m) +{ + bm->t = t; + bm->m = m; + bm->prb1 = -1 << (m + t); + bm->prb0 = ~bm->prb1; + bm->prb1 |= 1 << t; + bm->tmsk = (-1 << t) & 0xffff; + bm->prb0 &= bm->tmsk; + bm->prb1 &= bm->tmsk; + bm->ntm = ~bm->tmsk; + return; +} + +static int tek_rdget0(struct tek_STR_RNGDEC *rd, int n, int i) +{ + do { + while (rd->range < (UINT32) (1 << 24)) { + rd->range <<= 8; + rd->code = rd->code << 8 | *rd->p++; + } + rd->range >>= 1; + i += i; + if (rd->code >= rd->range) { + rd->code -= rd->range; + i |= 1; + } + } while (--n); + return ~i; +} + +static int tek_rdget1(struct tek_STR_RNGDEC *rd, tek_TPRB *prob0, int n, int j, struct tek_STR_BITMODEL *bm) +{ + UINT32 p, i, *prob, nm = n >> 4; + n &= 0x0f; + prob0 -= j; + do { + p = *(prob = prob0 + j); + if (bm->lt > 0) { + if (--bm->lt == 0) { + if (tek_rdget1(rd, &rd->probs.fchglt, 0x71, 0, &rd->bm[3]) == 0) { +err: + longjmp(rd->errjmp, 1); + } + i = bm - rd->bm; + if ((bm->s = tek_rdget1(rd, &rd->probs.fchgprm[i * 2 + bm->s], 0x71, 0, &rd->bm[1])) == 0) { + i = tek_rdget1(rd, rd->probs.tbmt, 0x74, 1, &rd->bm[2]) & 15; + if (i == 15) + goto err; + tek_setbm5(bm, i, ((tek_rdget1(rd, rd->probs.tbmm, 0x74, 1, &rd->bm[2]) - 1) & 15) + 1); + } + bm->lt = bm->lt0; + } + if (p < bm->prb0) { + p = bm->prb0; + goto fixprob; + } + if (p > bm->prb1) { + p = bm->prb1; + goto fixprob; + } + if (p & bm->ntm) { + p &= bm->tmsk; + fixprob: + *prob = p; + } + } + + while (rd->range < (UINT32) (1 << 24)) { + rd->range <<= 8; + rd->code = rd->code << 8 | *rd->p++; + } + j += j; + i = ((unsigned long long) (rd->range & rd->rmsk) * p) >> 16; + if (rd->code < i) { + j |= 1; + rd->range = i; + *prob += ((0x10000 - p) >> bm->m) & bm->tmsk; + } else { + rd->range -= i; + rd->code -= i; + *prob -= (p >> bm->m) & bm->tmsk; + } + --n; + if ((n & nm) == 0) + bm++; + } while (n); + return j; +} + +static UINT32 tek_revbit(UINT32 data, int len) +{ + UINT32 rev = 0; + do { + rev += rev + (data & 1); + data >>= 1; + } while (--len); + return rev; +} + +static int tek_getlen5(struct tek_STR_RNGDEC *rd, int m, int s_pos, int stk) +{ + int i; + if (tek_rdget1(rd, &rd->probs.lensel[m][0], 0x71, 0, rd->ptbm[3]) ^ stk) /* low */ + i = tek_rdget1(rd, rd->probs.pb[s_pos].lenlow[m], 0x73, 1, rd->ptbm[4]) & 7; + else if (tek_rdget1(rd, &rd->probs.lensel[m][1], 0x71, 0, rd->ptbm[3]) ^ stk) /* mid */ + i = tek_rdget1(rd, rd->probs.pb[s_pos].lenmid[m], 0x73, 1, rd->ptbm[5]); + else { + /* high */ + i = tek_rdget1(rd, rd->probs.lenhigh[m], 0x78, 1, rd->ptbm[6]) - (256 + 256 - 8); + if (i > 0) { + if (i < 6 && stk == 0) + i = tek_rdget1(rd, &rd->probs.lenext[(1 << i) - 2], i | 0x70, 1, rd->ptbm[7]) - 1; + else + i = tek_rdget0(rd, i, ~1) - 1; + i = tek_rdget0(rd, i, ~1) - 1; + } + i += 256 - 8 + 16; + } + return i; +} + +static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int pb, int lp, int flags) +{ + static int state_table[] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 }; + int i, j, k, pmch, rep[4], s, pos, m_pos = (1 << pb) - 1, m_lp = (1 << lp) - 1; + int stk = (flags == -1), lcr = 8 - lc, s_pos, lit0cntmsk = 0x78; + UINT32 *lit1; + struct tek_STR_RNGDEC *rd = (struct tek_STR_RNGDEC *) work; + struct tek_STR_PRB *prb = &rd->probs; + + rd->p = &src[4]; + rd->range |= -1; + rd->code = src[0] << 24 | src[1] << 16 | src[2] << 8 | src[3]; + for (i = 0; i < 4; i++) + rep[i] = ~i; + if (setjmp(rd->errjmp)) + goto err; + for (i = sizeof (struct tek_STR_PRB) / sizeof (tek_TPRB) + (0x300 << (lc + lp)) - 2; i >= 0; i--) + ((tek_TPRB *) prb)[i] = 1 << 15; + for (i = 0; i < 32; i++) { + rd->bm[i].lt = (i >= 4); + rd->bm[i].lt0 = (i < 24) ? 16 * 1024 : 8 * 1024; + rd->bm[i].s &= 0; + rd->bm[i].t = rd->bm[i].m = 5; + } + lit1 = prb->lit + ((256 << (lc + lp)) - 2); + if (stk) { + rd->rmsk = -1 << 11; + for (i = 0; i < 32; i++) + rd->bm[i].lt = 0; + for (i = 0; i < 14; i++) + rd->ptbm[i] = &rd->bm[0]; + } else { + UCHAR pt[14]; + static UCHAR pt1[14] = { + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 18, 18, 18, 8 + }; + static UCHAR pt2[14] = { + 8, 8, 10, 11, 12, 12, 14, 15, + 16, 16, 18, 18, 20, 21 + }; + /* + 0- 7:mch, mch, lit1, lensel, lenlow, lenmid, lenhigh, lenext + 8-15:pslot, pslot, sdis, sdis, align, rep-repg2 + */ + rd->rmsk |= -1; + rd->bm[1].t = 5; rd->bm[1].m = 3; /* for fchgprm */ + rd->bm[2].t = 9; rd->bm[2].m = 2; /* for tbmt, tbmm */ + if (flags & 0x40) { /* lt-flag */ + rd->bm[3].t = 0; rd->bm[3].m = 1; + prb->fchglt = 0xffff; + } + rd->bm[22].t = 0; rd->bm[22].m = 1; + prb->repg3 = 0xffff; + if (flags == -2) { /* z1 */ + rd->bm[22].lt = 0; + for (i = 0; i < 14; i++) + pt[i] = pt1[i]; + } else { + for (i = 0; i < 14; i++) + pt[i] = pt2[i]; + lit0cntmsk = (7 >> (flags & 3)) << 4 | 8; + pt[ 1] = 8 + ((flags & 0x04) != 0); /* mch */ + pt[ 5] = 12 + ((flags & 0x08) != 0); /* llm */ + pt[ 9] = 16 + ((flags & 0x10) != 0); /* pst */ + pt[11] = 18 + ((flags & 0x20) != 0); /* sds */ + } + for (i = 0; i < 14; i++) + rd->ptbm[i] = &rd->bm[pt[i]]; + } + for (i = 0; i < 32; i++) + tek_setbm5(&rd->bm[i], rd->bm[i].t, rd->bm[i].m); + + if ((tek_rdget1(rd, &prb->pb[0].st[0].mch, 0x71, 0, rd->ptbm[0]) ^ stk) == 0) + goto err; + *q++ = tek_rdget1(rd, prb->lit, lit0cntmsk, 1, &rd->bm[24]) & 0xff; + pmch &= 0; s &= 0; pos = 1; + while (pos < osiz) { + s_pos = pos & m_pos; + if (tek_rdget1(rd, &prb->pb[s_pos].st[s].mch, 0x71, 0, rd->ptbm[s > 0]) ^ stk) { + i = (q[-1] >> lcr | (pos & m_lp) << lc) << 8; + s = state_table[s]; + if (pmch == 0) + *q = tek_rdget1(rd, &prb->lit[i], lit0cntmsk, 1, &rd->bm[24]) & 0xff; + else { + struct tek_STR_BITMODEL *bm = &rd->bm[24]; + j = 1; + k = 8; + pmch = q[rep[0]]; + do { + j += j + tek_rdget1(rd, &lit1[(i + j) << 1 | pmch >> 7], 0x71, 0, rd->ptbm[2]); + k--; + if ((k & (lit0cntmsk >> 4)) == 0) + bm++; + if ((((pmch >> 7) ^ j) & 1) != 0 && k != 0) { + j = tek_rdget1(rd, &prb->lit[i + j - 1], k | (lit0cntmsk & 0x70), j, bm); + break; + } + pmch <<= 1; + } while (k); + *q = j & 0xff; + pmch &= 0; + } + pos++; + q++; + } else { /* lz */ + pmch |= 1; + if (tek_rdget1(rd, &prb->st[s].rep, 0x71, 0, rd->ptbm[13]) ^ stk) { /* len/dis */ + rep[3] = rep[2]; + rep[2] = rep[1]; + rep[1] = rep[0]; + j = i = tek_getlen5(rd, 0, s_pos, stk); + s = s < 7 ? 7 : 10; + if (j >= 4) + j = 3; + rep[0] = j = tek_rdget1(rd, prb->pslot[j], 0x76, 1, rd->ptbm[8 + (j == 3)]) & 0x3f; + if (j >= 4) { + k = (j >> 1) - 1; /* k = [1, 30] */ + rep[0] = (2 | (j & 1)) << k; + if (j < 14) /* k < 6 */ + rep[0] |= tek_revbit(tek_rdget1(rd, &prb->spdis[j & 1][(1 << k) - 2], k | 0x70, 1, rd->ptbm[10 + (k >= 4)]), k); + else { + if (stk == 0) { + if (k -= 6) + rep[0] |= tek_rdget0(rd, k, ~0) << 6; + rep[0] |= tek_revbit(tek_rdget1(rd, prb->algn, 0x76, 1, rd->ptbm[12]), 6); + } else { + rep[0] |= tek_rdget0(rd, k - 4, ~0) << 4; + rep[0] |= tek_revbit(tek_rdget1(rd, prb->algn, 0x74, 1, rd->ptbm[12]), 4); + } + } + } + rep[0] = ~rep[0]; + } else { /* repeat-dis */ + if (tek_rdget1(rd, &prb->st[s].repg0, 0x71, 0, rd->ptbm[13]) ^ stk) { /* rep0 */ + i |= -1; + if (tek_rdget1(rd, &prb->pb[s_pos].st[s].rep0l1, 0x71, 0, rd->ptbm[13]) == 0) { + s = s < 7 ? 9 : 11; + goto skip; + } + } else { + if (tek_rdget1(rd, &prb->st[s].repg1, 0x71, 0, rd->ptbm[13]) ^ stk) /* rep1 */ + i = rep[1]; + else { + if (tek_rdget1(rd, &prb->st[s].repg2, 0x71, 0, rd->ptbm[13]) ^ stk) /* rep2 */ + i = rep[2]; + else { + if (stk == 0) { + if (tek_rdget1(rd, &prb->repg3, 0x71, 0, &rd->bm[22]) == 0) + goto err; + } + i = rep[3]; /* rep3 */ + rep[3] = rep[2]; + } + rep[2] = rep[1]; + } + rep[1] = rep[0]; + rep[0] = i; + } + i = tek_getlen5(rd, 1, s_pos, stk); + s = s < 7 ? 8 : 11; + } +skip: + i += 2; + if (pos + rep[0] < 0) + goto err; + if (pos + i > osiz) + i = osiz - pos; + pos += i; + do { + *q = q[rep[0]]; + q++; + } while (--i); + } + } + return 0; +err: + return 1; +} + +static int tek_decode5(int siz, UCHAR *p, UCHAR *q) +{ + UCHAR *p1 = p + siz; + int dsiz, hed, bsiz, st = 0; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + if ((hed & 1) == 0) + st = tek_lzrestore_tek5(p1 - p + 1, p - 1, dsiz, q); + else { + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (hed & 0x20) + return 1; + if (bsiz == 256) + st = tek_lzrestore_tek5(p1 - p, p, dsiz, q); + else { + if (dsiz > bsiz) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + st = tek_lzrestore_tek5(p1 - p, p, dsiz, q); + } + } + } + return st; +} diff --git a/29_day/winhelo/Makefile b/29_day/winhelo/Makefile index 44ac359..91d9264 100644 --- a/29_day/winhelo/Makefile +++ b/29_day/winhelo/Makefile @@ -3,3 +3,7 @@ STACK = 8k MALLOC = 0k include ../app_make.txt + +$(APP).hrb : $(APP).org Makefile + $(COPY) $(APP).org $(APP).hrb + \ No newline at end of file From 9df2b90ad36019100425b04f0b50fa62a7954706 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Thu, 19 May 2016 13:07:37 +0800 Subject: [PATCH 57/83] clean files --- 29_day/Makefile | 7 +-- 29_day/haribote/Makefile | 4 -- 29_day/haribote/ipl10.nas | 109 ------------------------------------ 29_day/haribote/jp.nas | 2 +- 29_day/typeipl/!cons_9x.bat | 1 - 29_day/typeipl/!cons_nt.bat | 1 - 29_day/typeipl/Makefile | 5 -- 29_day/typeipl/make.bat | 1 - 29_day/typeipl/typeipl.c | 17 ------ 9 files changed, 2 insertions(+), 145 deletions(-) delete mode 100644 29_day/haribote/ipl10.nas delete mode 100644 29_day/typeipl/!cons_9x.bat delete mode 100644 29_day/typeipl/!cons_nt.bat delete mode 100644 29_day/typeipl/Makefile delete mode 100644 29_day/typeipl/make.bat delete mode 100644 29_day/typeipl/typeipl.c diff --git a/29_day/Makefile b/29_day/Makefile index e6b82cf..ff541d5 100644 --- a/29_day/Makefile +++ b/29_day/Makefile @@ -21,8 +21,7 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ lines/lines.hrb walk/walk.hrb noodle/noodle.hrb \ beepdown/beepdown.hrb color/color.hrb color2/color2.hrb \ sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb \ - typeipl/typeipl.hrb type/type.hrb iroha/iroha.hrb \ - chklang/chklang.hrb + type/type.hrb iroha/iroha.hrb chklang/chklang.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:haribote/ipl20.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ @@ -47,7 +46,6 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ copy from:sosu/sosu.hrb to:@: \ copy from:sosu2/sosu2.hrb to:@: \ copy from:sosu3/sosu3.hrb to:@: \ - copy from:typeipl/typeipl.hrb to:@: \ copy from:type/type.hrb to:@: \ copy from:iroha/iroha.hrb to:@: \ copy from:chklang/chklang.hrb to:@: \ @@ -88,7 +86,6 @@ full : $(MAKE) -C sosu $(MAKE) -C sosu2 $(MAKE) -C sosu3 - $(MAKE) -C typeipl $(MAKE) -C type $(MAKE) -C iroha $(MAKE) -C chklang @@ -136,7 +133,6 @@ clean_full : $(MAKE) -C sosu clean $(MAKE) -C sosu2 clean $(MAKE) -C sosu3 clean - $(MAKE) -C typeipl clean $(MAKE) -C type clean $(MAKE) -C iroha clean $(MAKE) -C chklang clean @@ -163,7 +159,6 @@ src_only_full : $(MAKE) -C sosu src_only $(MAKE) -C sosu2 src_only $(MAKE) -C sosu3 src_only - $(MAKE) -C typeipl src_only $(MAKE) -C type src_only $(MAKE) -C iroha src_only $(MAKE) -C chklang src_only diff --git a/29_day/haribote/Makefile b/29_day/haribote/Makefile index a5dd10c..6844a71 100644 --- a/29_day/haribote/Makefile +++ b/29_day/haribote/Makefile @@ -28,9 +28,6 @@ default : # 镜像文件生成 -ipl10.bin : ipl10.nas Makefile - $(NASK) ipl10.nas ipl10.bin ipl10.lst - ipl20.bin : ipl20.nas Makefile $(NASK) ipl20.nas ipl20.bin ipl20.lst @@ -78,6 +75,5 @@ clean : src_only : $(MAKE) clean - -$(DEL) ipl10.bin -$(DEL) ipl20.bin -$(DEL) haribote.sys diff --git a/29_day/haribote/ipl10.nas b/29_day/haribote/ipl10.nas deleted file mode 100644 index 7108a21..0000000 --- a/29_day/haribote/ipl10.nas +++ /dev/null @@ -1,109 +0,0 @@ -; haribote-ipl -; TAB=4 - -CYLS EQU 10 ; 声明CYLS=10 - - ORG 0x7c00 ; 指明程序装载地址 - -; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code - - JMP entry - DB 0x90 - DB "HARIBOTE" ; 启动扇区名称(8字节) - DW 512 ; 每个扇区(sector)大小(必须512字节) - DB 1 ; 簇(cluster)大小(必须为1个扇区) - DW 1 ; FAT起始位置(一般为第一个扇区) - DB 2 ; FAT个数(必须为2) - DW 224 ; 根目录大小(一般为224项) - DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512) - DB 0xf0 ; 磁盘类型(必须为0xf0) - DW 9 ; FAT的长度(必??9扇区) - DW 18 ; 一个磁道(track)有几个扇区(必须为18) - DW 2 ; 磁头数(必??2) - DD 0 ; 不使用分区,必须是0 - DD 2880 ; 重写一次磁盘大小 - DB 0,0,0x29 ; 意义不明(固定) - DD 0xffffffff ; (可能是)卷标号码 - DB "HARIBOTEOS " ; 磁盘的名称(必须为11字?,不足填空格) - DB "FAT12 " ; 磁盘格式名称(必??8字?,不足填空格) - RESB 18 ; 先空出18字节 - -; 程序主体 - -entry: - MOV AX,0 ; 初始化寄存器 - MOV SS,AX - MOV SP,0x7c00 - MOV DS,AX - -; 读取磁盘 - - MOV AX,0x0820 - MOV ES,AX - MOV CH,0 ; 柱面0 - MOV DH,0 ; 磁头0 - MOV CL,2 ; 扇区2 - -readloop: - MOV SI,0 ; 记录失败次数寄存器 - -retry: - MOV AH,0x02 ; AH=0x02 : 读入磁盘 - MOV AL,1 ; 1个扇区 - MOV BX,0 - MOV DL,0x00 ; A驱动器 - INT 0x13 ; 调用磁盘BIOS - JNC next ; 没出错则跳转到fin - ADD SI,1 ; 往SI加1 - CMP SI,5 ; 比较SI与5 - JAE error ; SI >= 5 跳转到error - MOV AH,0x00 - MOV DL,0x00 ; A驱动器 - INT 0x13 ; 重置驱动器 - JMP retry -next: - MOV AX,ES ; 把内存地址后移0x200(512/16十六进制转换) - ADD AX,0x0020 - MOV ES,AX ; ADD ES,0x020因为没有ADD ES,只能通过AX进行 - ADD CL,1 ; 往CL里面加1 - CMP CL,18 ; 比较CL与18 - JBE readloop ; CL <= 18 跳转到readloop - MOV CL,1 - ADD DH,1 - CMP DH,2 - JB readloop ; DH < 2 跳转到readloop - MOV DH,0 - ADD CH,1 - CMP CH,CYLS - JB readloop ; CH < CYLS 跳转到readloop - -; 读取完毕,跳转到haribote.sys执行! - MOV [0x0ff0],CH ; IPLがどこまで読んだのかをメモ - JMP 0xc200 - -error: - MOV SI,msg - -putloop: - MOV AL,[SI] - ADD SI,1 ; 给SI加1 - CMP AL,0 - JE fin - MOV AH,0x0e ; 显示一个文字 - MOV BX,15 ; 指定字符颜色 - INT 0x10 ; 调用显卡BIOS - JMP putloop - -fin: - HLT ; 让CPU停止,等待指令 - JMP fin ; 无限循环 - -msg: - DB 0x0a, 0x0a ; 换行两次 - DB "load error" - DB 0x0a ; 换行 - DB 0 - - RESB 0x7dfe-$ ; 填写0x00直到0x001fe - - DB 0x55, 0xaa diff --git a/29_day/haribote/jp.nas b/29_day/haribote/jp.nas index 3f7cb00..2662459 100644 --- a/29_day/haribote/jp.nas +++ b/29_day/haribote/jp.nas @@ -1,7 +1,7 @@ ; haribote-ipl ; TAB=4 -CYLS EQU 10 ; ǂ܂œǂݍނ +CYLS EQU 20 ; ǂ܂œǂݍނ ORG 0x7c00 ; ̃vOǂɓǂݍ܂̂ diff --git a/29_day/typeipl/!cons_9x.bat b/29_day/typeipl/!cons_9x.bat deleted file mode 100644 index e42252a..0000000 --- a/29_day/typeipl/!cons_9x.bat +++ /dev/null @@ -1 +0,0 @@ -command \ No newline at end of file diff --git a/29_day/typeipl/!cons_nt.bat b/29_day/typeipl/!cons_nt.bat deleted file mode 100644 index 6e07473..0000000 --- a/29_day/typeipl/!cons_nt.bat +++ /dev/null @@ -1 +0,0 @@ -cmd.exe \ No newline at end of file diff --git a/29_day/typeipl/Makefile b/29_day/typeipl/Makefile deleted file mode 100644 index f5b423e..0000000 --- a/29_day/typeipl/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -APP = typeipl -STACK = 1k -MALLOC = 0k - -include ../app_make.txt diff --git a/29_day/typeipl/make.bat b/29_day/typeipl/make.bat deleted file mode 100644 index 6b0dbfc..0000000 --- a/29_day/typeipl/make.bat +++ /dev/null @@ -1 +0,0 @@ -..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/typeipl/typeipl.c b/29_day/typeipl/typeipl.c deleted file mode 100644 index 90a0273..0000000 --- a/29_day/typeipl/typeipl.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "apilib.h" - -void HariMain(void) -{ - int fh; - char c; - fh = api_fopen("ipl10.nas"); - if (fh != 0) { - for (;;) { - if (api_fread(&c, 1, fh) == 0) { - break; - } - api_putchar(c); - } - } - api_end(); -} From 203dd63152150f1863a160b617cd13903b2cb68e Mon Sep 17 00:00:00 2001 From: Yourtion Date: Thu, 19 May 2016 14:05:01 +0800 Subject: [PATCH 58/83] =?UTF-8?q?=E6=A0=87=E5=87=86=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 29_day/Makefile | 3 +++ 29_day/app_make.txt | 13 +++++++--- 29_day/hello4/Makefile | 2 +- 29_day/hello4/hello4.c | 6 ++--- 29_day/stdlib.h | 4 +++ 29_day/stdlib/!cons_9x.bat | 1 + 29_day/stdlib/!cons_nt.bat | 1 + 29_day/stdlib/Makefile | 50 +++++++++++++++++++++++++++++++++++++ 29_day/stdlib/make.bat | 1 + 29_day/stdlib/stdlib.c | 51 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 29_day/stdlib.h create mode 100644 29_day/stdlib/!cons_9x.bat create mode 100644 29_day/stdlib/!cons_nt.bat create mode 100644 29_day/stdlib/Makefile create mode 100644 29_day/stdlib/make.bat create mode 100644 29_day/stdlib/stdlib.c diff --git a/29_day/Makefile b/29_day/Makefile index ff541d5..af3fc84 100644 --- a/29_day/Makefile +++ b/29_day/Makefile @@ -67,6 +67,7 @@ install : full : $(MAKE) -C haribote $(MAKE) -C apilib + $(MAKE) -C stdlib $(MAKE) -C a $(MAKE) -C hello3 $(MAKE) -C hello4 @@ -114,6 +115,7 @@ src_only : clean_full : $(MAKE) -C haribote clean $(MAKE) -C apilib clean + $(MAKE) -C stdlib clean $(MAKE) -C a clean $(MAKE) -C hello3 clean $(MAKE) -C hello4 clean @@ -140,6 +142,7 @@ clean_full : src_only_full : $(MAKE) -C haribote src_only $(MAKE) -C apilib src_only + $(MAKE) -C stdlib src_only $(MAKE) -C a src_only $(MAKE) -C hello3 src_only $(MAKE) -C hello4 src_only diff --git a/29_day/app_make.txt b/29_day/app_make.txt index 30421f4..b1e4436 100644 --- a/29_day/app_make.txt +++ b/29_day/app_make.txt @@ -1,6 +1,7 @@ TOOLPATH = ../../z_tools/ INCPATH = ../../z_tools/haribote/ APILIBPATH = ../apilib/ +STDLIBPATH = ../stdlib/ HARIBOTEPATH = ../haribote/ MAKE = $(TOOLPATH)make.exe -r @@ -26,9 +27,13 @@ default : #文件生成规则 -$(APP).bim : $(APP).obj $(APILIBPATH)apilib.lib Makefile ../app_make.txt +$(APP).bim : $(APP).obj $(APILIBPATH)apilib.lib $(STDLIBPATH)stdlib.lib Makefile ../app_make.txt $(OBJ2BIM) @$(RULEFILE) out:$(APP).bim map:$(APP).map stack:$(STACK) \ - $(APP).obj $(APILIBPATH)apilib.lib + $(APP).obj $(APILIBPATH)apilib.lib $(STDLIBPATH)stdlib.lib + +$(STDAPP).bim : $(APP).obj $(STDLIBPATH)stdlib.lib Makefile ../app_make.txt + $(OBJ2BIM) @$(RULEFILE) out:$(APP).bim map:$(APP).map stack:$(STACK) \ + $(APP).obj $(STDLIBPATH)stdlib.lib haribote.img : ../haribote/ipl20.bin ../haribote/haribote.sys $(APP).hrb \ Makefile ../app_make.txt @@ -41,7 +46,7 @@ haribote.img : ../haribote/ipl20.bin ../haribote/haribote.sys $(APP).hrb \ #一般规则 -%.gas : %.c ../apilib.h Makefile ../app_make.txt +%.gas : %.c ../apilib.h ../stdlib.h Makefile ../app_make.txt $(CC1) -o $*.gas $*.c %.nas : %.gas Makefile ../app_make.txt @@ -65,10 +70,12 @@ run : full : $(MAKE) -C $(APILIBPATH) + $(MAKE) -C $(STDLIBPATH) $(MAKE) $(APP).hrb run_full : $(MAKE) -C $(APILIBPATH) + $(MAKE) -C $(STDLIBPATH) $(MAKE) -C ../haribote $(MAKE) run diff --git a/29_day/hello4/Makefile b/29_day/hello4/Makefile index 557a184..ade47c9 100644 --- a/29_day/hello4/Makefile +++ b/29_day/hello4/Makefile @@ -4,5 +4,5 @@ MALLOC = 0k include ../app_make.txt -$(APP).hrb : $(APP).org Makefile +$(STDAPP).hrb : $(APP).org Makefile $(COPY) $(APP).org $(APP).hrb diff --git a/29_day/hello4/hello4.c b/29_day/hello4/hello4.c index ec04384..5a69068 100644 --- a/29_day/hello4/hello4.c +++ b/29_day/hello4/hello4.c @@ -1,7 +1,7 @@ -#include "apilib.h" +#include "stdlib.h" void HariMain(void) { - api_putstr0("hello, world\n"); - api_end(); + printf("hello, world : %s %d\n", "aaa", 10); + exit(0); } diff --git a/29_day/stdlib.h b/29_day/stdlib.h new file mode 100644 index 0000000..e55f70c --- /dev/null +++ b/29_day/stdlib.h @@ -0,0 +1,4 @@ +int putchar(int c); +void exit(int status); +int printf(char *format, ...); +void *malloc(int size); \ No newline at end of file diff --git a/29_day/stdlib/!cons_9x.bat b/29_day/stdlib/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/stdlib/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/stdlib/!cons_nt.bat b/29_day/stdlib/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/stdlib/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/stdlib/Makefile b/29_day/stdlib/Makefile new file mode 100644 index 0000000..faee897 --- /dev/null +++ b/29_day/stdlib/Makefile @@ -0,0 +1,50 @@ +OBJS_API = stdlib.obj + +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) stdlib.lib + +#库生成规则 + +stdlib.lib : Makefile $(OBJS_API) + $(GOLIB) $(OBJS_API) out:stdlib.lib + +#文件生成规则 + +%.gas : %.c ../stdlib.h Makefile + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +#命令 + +clean : + -$(DEL) *.lst + -$(DEL) *.obj + +src_only : + $(MAKE) clean + -$(DEL) stdlib.lib \ No newline at end of file diff --git a/29_day/stdlib/make.bat b/29_day/stdlib/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/stdlib/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/stdlib/stdlib.c b/29_day/stdlib/stdlib.c new file mode 100644 index 0000000..5bbeae6 --- /dev/null +++ b/29_day/stdlib/stdlib.c @@ -0,0 +1,51 @@ +#include "../apilib.h" +#include "../stdlib.h" + +#include +#include + +int putchar(int c) +{ + api_putchar(c); + return c; +} + +void exit(int status) +{ + api_end(); +} + +int printf(char *format, ...) +{ + va_list ap; + char s[1000]; + int i; + + va_start(ap, format); + i = vsprintf(s, format, ap); + api_putstr0(s); + va_end(ap); + return i; +} + +void *malloc(int size) +{ + char *p = api_malloc(size + 16); + if (p != 0) { + *((int *) p) = size; + p += 16; + } + return p; +} + +void free(void *p) +{ + char *q = p; + int size; + if (q != 0) { + q -= 16; + size = *((int *) q); + api_free(q, size + 16); + } + return; +} \ No newline at end of file From 73b7421cf2d57b3018cf9f22193bbc6ae23eb965 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Thu, 19 May 2016 14:08:59 +0800 Subject: [PATCH 59/83] =?UTF-8?q?=E9=9D=9E=E7=9F=A9=E5=BD=A2=E7=AA=97?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 29_day/Makefile | 4 ++++ 29_day/notrec/!cons_9x.bat | 1 + 29_day/notrec/!cons_nt.bat | 1 + 29_day/notrec/Makefile | 5 +++++ 29_day/notrec/make.bat | 1 + 29_day/notrec/notrec.c | 17 +++++++++++++++++ 6 files changed, 29 insertions(+) create mode 100644 29_day/notrec/!cons_9x.bat create mode 100644 29_day/notrec/!cons_nt.bat create mode 100644 29_day/notrec/Makefile create mode 100644 29_day/notrec/make.bat create mode 100644 29_day/notrec/notrec.c diff --git a/29_day/Makefile b/29_day/Makefile index af3fc84..e37ec29 100644 --- a/29_day/Makefile +++ b/29_day/Makefile @@ -49,6 +49,7 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ copy from:type/type.hrb to:@: \ copy from:iroha/iroha.hrb to:@: \ copy from:chklang/chklang.hrb to:@: \ + copy from:notrec/notrec.hrb to:@: \ copy from:euc.txt to:@: \ copy from:nihongo/nihongo.fnt to:@: \ imgout:haribote.img @@ -90,6 +91,7 @@ full : $(MAKE) -C type $(MAKE) -C iroha $(MAKE) -C chklang + $(MAKE) -C notrec $(MAKE) haribote.img run_full : @@ -138,6 +140,7 @@ clean_full : $(MAKE) -C type clean $(MAKE) -C iroha clean $(MAKE) -C chklang clean + $(MAKE) -C notrec clean src_only_full : $(MAKE) -C haribote src_only @@ -165,6 +168,7 @@ src_only_full : $(MAKE) -C type src_only $(MAKE) -C iroha src_only $(MAKE) -C chklang src_only + $(MAKE) -C notrec src_only -$(DEL) haribote.img refresh : diff --git a/29_day/notrec/!cons_9x.bat b/29_day/notrec/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/notrec/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/notrec/!cons_nt.bat b/29_day/notrec/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/notrec/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/notrec/Makefile b/29_day/notrec/Makefile new file mode 100644 index 0000000..7d7d3f0 --- /dev/null +++ b/29_day/notrec/Makefile @@ -0,0 +1,5 @@ +APP = notrec +STACK = 11k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/notrec/make.bat b/29_day/notrec/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/notrec/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/notrec/notrec.c b/29_day/notrec/notrec.c new file mode 100644 index 0000000..35ae0de --- /dev/null +++ b/29_day/notrec/notrec.c @@ -0,0 +1,17 @@ +#include "apilib.h" + +void HariMain(void) +{ + int win; + char buf[150 * 70]; + win = api_openwin(buf, 150, 70, 255, "notrec"); + api_boxfilwin(win, 0, 50, 34, 69, 255); + api_boxfilwin(win, 115, 50, 149, 69, 255); + api_boxfilwin(win, 50, 30, 99, 49, 255); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} From 0adab9385e465afaefb9629e9f8a64915dbd71df Mon Sep 17 00:00:00 2001 From: Yourtion Date: Thu, 19 May 2016 14:13:37 +0800 Subject: [PATCH 60/83] bball --- 29_day/Makefile | 88 ++++++++++++++++++++------------------- 29_day/bball/!cons_9x.bat | 1 + 29_day/bball/!cons_nt.bat | 1 + 29_day/bball/Makefile | 5 +++ 29_day/bball/bball.c | 37 ++++++++++++++++ 29_day/bball/make.bat | 1 + 29_day/haribote/console.c | 10 +++++ 7 files changed, 100 insertions(+), 43 deletions(-) create mode 100644 29_day/bball/!cons_9x.bat create mode 100644 29_day/bball/!cons_nt.bat create mode 100644 29_day/bball/Makefile create mode 100644 29_day/bball/bball.c create mode 100644 29_day/bball/make.bat diff --git a/29_day/Makefile b/29_day/Makefile index e37ec29..1963c4e 100644 --- a/29_day/Makefile +++ b/29_day/Makefile @@ -21,7 +21,8 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ lines/lines.hrb walk/walk.hrb noodle/noodle.hrb \ beepdown/beepdown.hrb color/color.hrb color2/color2.hrb \ sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb \ - type/type.hrb iroha/iroha.hrb chklang/chklang.hrb + type/type.hrb iroha/iroha.hrb chklang/chklang.hrb \ + notrec/notrec.hrb bball/bball.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:haribote/ipl20.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ @@ -49,8 +50,9 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ copy from:type/type.hrb to:@: \ copy from:iroha/iroha.hrb to:@: \ copy from:chklang/chklang.hrb to:@: \ - copy from:notrec/notrec.hrb to:@: \ copy from:euc.txt to:@: \ + copy from:notrec/notrec.hrb to:@: \ + copy from:bball/bball.hrb to:@: \ copy from:nihongo/nihongo.fnt to:@: \ imgout:haribote.img @@ -68,7 +70,6 @@ install : full : $(MAKE) -C haribote $(MAKE) -C apilib - $(MAKE) -C stdlib $(MAKE) -C a $(MAKE) -C hello3 $(MAKE) -C hello4 @@ -92,6 +93,7 @@ full : $(MAKE) -C iroha $(MAKE) -C chklang $(MAKE) -C notrec + $(MAKE) -C bball $(MAKE) haribote.img run_full : @@ -116,59 +118,59 @@ src_only : clean_full : $(MAKE) -C haribote clean - $(MAKE) -C apilib clean - $(MAKE) -C stdlib clean - $(MAKE) -C a clean - $(MAKE) -C hello3 clean - $(MAKE) -C hello4 clean - $(MAKE) -C hello5 clean + $(MAKE) -C apilib clean + $(MAKE) -C a clean + $(MAKE) -C hello3 clean + $(MAKE) -C hello4 clean + $(MAKE) -C hello5 clean $(MAKE) -C winhelo clean $(MAKE) -C winhelo2 clean $(MAKE) -C winhelo3 clean - $(MAKE) -C star1 clean - $(MAKE) -C stars clean - $(MAKE) -C stars2 clean - $(MAKE) -C lines clean - $(MAKE) -C walk clean - $(MAKE) -C noodle clean + $(MAKE) -C star1 clean + $(MAKE) -C stars clean + $(MAKE) -C stars2 clean + $(MAKE) -C lines clean + $(MAKE) -C walk clean + $(MAKE) -C noodle clean $(MAKE) -C beepdown clean - $(MAKE) -C color clean - $(MAKE) -C color2 clean - $(MAKE) -C sosu clean - $(MAKE) -C sosu2 clean - $(MAKE) -C sosu3 clean - $(MAKE) -C type clean - $(MAKE) -C iroha clean + $(MAKE) -C color clean + $(MAKE) -C color2 clean + $(MAKE) -C sosu clean + $(MAKE) -C sosu2 clean + $(MAKE) -C sosu3 clean + $(MAKE) -C type clean + $(MAKE) -C iroha clean $(MAKE) -C chklang clean - $(MAKE) -C notrec clean + $(MAKE) -C notrec clean + $(MAKE) -C bball clean src_only_full : $(MAKE) -C haribote src_only - $(MAKE) -C apilib src_only - $(MAKE) -C stdlib src_only - $(MAKE) -C a src_only - $(MAKE) -C hello3 src_only - $(MAKE) -C hello4 src_only - $(MAKE) -C hello5 src_only + $(MAKE) -C apilib src_only + $(MAKE) -C a src_only + $(MAKE) -C hello3 src_only + $(MAKE) -C hello4 src_only + $(MAKE) -C hello5 src_only $(MAKE) -C winhelo src_only $(MAKE) -C winhelo2 src_only $(MAKE) -C winhelo3 src_only - $(MAKE) -C star1 src_only - $(MAKE) -C stars src_only - $(MAKE) -C stars2 src_only - $(MAKE) -C lines src_only - $(MAKE) -C walk src_only - $(MAKE) -C noodle src_only + $(MAKE) -C star1 src_only + $(MAKE) -C stars src_only + $(MAKE) -C stars2 src_only + $(MAKE) -C lines src_only + $(MAKE) -C walk src_only + $(MAKE) -C noodle src_only $(MAKE) -C beepdown src_only - $(MAKE) -C color src_only - $(MAKE) -C color2 src_only - $(MAKE) -C sosu src_only - $(MAKE) -C sosu2 src_only - $(MAKE) -C sosu3 src_only - $(MAKE) -C type src_only - $(MAKE) -C iroha src_only + $(MAKE) -C color src_only + $(MAKE) -C color2 src_only + $(MAKE) -C sosu src_only + $(MAKE) -C sosu2 src_only + $(MAKE) -C sosu3 src_only + $(MAKE) -C type src_only + $(MAKE) -C iroha src_only $(MAKE) -C chklang src_only - $(MAKE) -C notrec src_only + $(MAKE) -C notrec src_only + $(MAKE) -C bball src_only -$(DEL) haribote.img refresh : diff --git a/29_day/bball/!cons_9x.bat b/29_day/bball/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/bball/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/bball/!cons_nt.bat b/29_day/bball/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/bball/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/bball/Makefile b/29_day/bball/Makefile new file mode 100644 index 0000000..b976252 --- /dev/null +++ b/29_day/bball/Makefile @@ -0,0 +1,5 @@ +APP = bball +STACK = 52k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/bball/bball.c b/29_day/bball/bball.c new file mode 100644 index 0000000..23a5d67 --- /dev/null +++ b/29_day/bball/bball.c @@ -0,0 +1,37 @@ +#include "apilib.h" + +void HariMain(void) +{ + int win, i, j, dis; + char buf[216 * 237]; + struct POINT { + int x, y; + }; + static struct POINT table[16] = { + { 204, 129 }, { 195, 90 }, { 172, 58 }, { 137, 38 }, { 98, 34 }, + { 61, 46 }, { 31, 73 }, { 15, 110 }, { 15, 148 }, { 31, 185 }, + { 61, 212 }, { 98, 224 }, { 137, 220 }, { 172, 200 }, { 195, 168 }, + { 204, 129 } + }; + + win = api_openwin(buf, 216, 237, -1, "bball"); + api_boxfilwin(win, 8, 29, 207, 228, 0); + for (i = 0; i <= 14; i++) { + for (j = i + 1; j <= 15; j++) { + dis = j - i; /*两点间的距离*/ + if (dis >= 8) { + dis = 15 - dis; /*逆向计数*/ + } + if (dis != 0) { + api_linewin(win, table[i].x, table[i].y, table[j].x, table[j].y, 8 - dis); + } + } + } + + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/29_day/bball/make.bat b/29_day/bball/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/bball/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/29_day/haribote/console.c b/29_day/haribote/console.c index 44047b0..3e51686 100644 --- a/29_day/haribote/console.c +++ b/29_day/haribote/console.c @@ -489,6 +489,16 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int sht = (struct SHEET *) (ebx & 0xfffffffe); hrb_api_linewin(sht, eax, ecx, esi, edi, ebp); if ((ebx & 1) == 0) { + if (eax > esi) { + i = eax; + eax = esi; + esi = i; + } + if (ecx > edi) { + i = ecx; + ecx = edi; + edi = i; + } sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); } } else if (edx == 14) { From 6b0457bed643480d6c7cfc28d5f9cefce56061c1 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Thu, 19 May 2016 14:22:52 +0800 Subject: [PATCH 61/83] =?UTF-8?q?=E5=A4=96=E6=98=9F=E4=BA=BA=E6=B8=B8?= =?UTF-8?q?=E6=88=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 29_day/Makefile | 6 +- 29_day/invader/!cons_9x.bat | 1 + 29_day/invader/!cons_nt.bat | 1 + 29_day/invader/Makefile | 5 + 29_day/invader/invader.c | 281 ++++++++++++++++++++++++++++++++++++ 29_day/invader/make.bat | 1 + 6 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 29_day/invader/!cons_9x.bat create mode 100644 29_day/invader/!cons_nt.bat create mode 100644 29_day/invader/Makefile create mode 100644 29_day/invader/invader.c create mode 100644 29_day/invader/make.bat diff --git a/29_day/Makefile b/29_day/Makefile index 1963c4e..f92b3d5 100644 --- a/29_day/Makefile +++ b/29_day/Makefile @@ -22,7 +22,7 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ beepdown/beepdown.hrb color/color.hrb color2/color2.hrb \ sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb \ type/type.hrb iroha/iroha.hrb chklang/chklang.hrb \ - notrec/notrec.hrb bball/bball.hrb + notrec/notrec.hrb bball/bball.hrb invader/invader.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:haribote/ipl20.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ @@ -53,6 +53,7 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ copy from:euc.txt to:@: \ copy from:notrec/notrec.hrb to:@: \ copy from:bball/bball.hrb to:@: \ + copy from:invader/invader.hrb to:@: \ copy from:nihongo/nihongo.fnt to:@: \ imgout:haribote.img @@ -94,6 +95,7 @@ full : $(MAKE) -C chklang $(MAKE) -C notrec $(MAKE) -C bball + $(MAKE) -C invader $(MAKE) haribote.img run_full : @@ -143,6 +145,7 @@ clean_full : $(MAKE) -C chklang clean $(MAKE) -C notrec clean $(MAKE) -C bball clean + $(MAKE) -C invader clean src_only_full : $(MAKE) -C haribote src_only @@ -171,6 +174,7 @@ src_only_full : $(MAKE) -C chklang src_only $(MAKE) -C notrec src_only $(MAKE) -C bball src_only + $(MAKE) -C invader src_only -$(DEL) haribote.img refresh : diff --git a/29_day/invader/!cons_9x.bat b/29_day/invader/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/29_day/invader/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/29_day/invader/!cons_nt.bat b/29_day/invader/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/29_day/invader/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/29_day/invader/Makefile b/29_day/invader/Makefile new file mode 100644 index 0000000..a60ffdb --- /dev/null +++ b/29_day/invader/Makefile @@ -0,0 +1,5 @@ +APP = invader +STACK = 90k +MALLOC = 0k + +include ../app_make.txt diff --git a/29_day/invader/invader.c b/29_day/invader/invader.c new file mode 100644 index 0000000..d26d3b1 --- /dev/null +++ b/29_day/invader/invader.c @@ -0,0 +1,281 @@ +#include /* sprintf */ +#include /* strlen */ +#include "apilib.h" + +void putstr(int win, char *winbuf, int x, int y, int col, unsigned char *s); +void wait(int i, int timer, char *keyflag); + +static unsigned char charset[16 * 8] = { + + /* invader(0) */ + 0x00, 0x00, 0x00, 0x43, 0x5f, 0x5f, 0x5f, 0x7f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x20, 0x3f, 0x00, + + /* invader(1) */ + 0x00, 0x0f, 0x7f, 0xff, 0xcf, 0xcf, 0xcf, 0xff, + 0xff, 0xe0, 0xff, 0xff, 0xc0, 0xc0, 0xc0, 0x00, + + /* invader(2) */ + 0x00, 0xf0, 0xfe, 0xff, 0xf3, 0xf3, 0xf3, 0xff, + 0xff, 0x07, 0xff, 0xff, 0x03, 0x03, 0x03, 0x00, + + /* invader(3) */ + 0x00, 0x00, 0x00, 0xc2, 0xfa, 0xfa, 0xfa, 0xfe, + 0xf8, 0xf8, 0xf8, 0xf8, 0x00, 0x04, 0xfc, 0x00, + + /* fighter(0) */ + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x43, 0x47, 0x4f, 0x5f, 0x7f, 0x7f, 0x00, + + /* fighter(1) */ + 0x18, 0x7e, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, + 0xff, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0x00, + + /* fighter(2) */ + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0xc2, 0xe2, 0xf2, 0xfa, 0xfe, 0xfe, 0x00, + + /* laser */ + 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00 +}; +/* invader:"abcd", fighter:"efg", laser:"h" */ + +void HariMain(void) +{ + /* + fx:自机的x坐标(fighter_x) + lx,ly:等离子炮弹的坐标(laser_x,laser_y) + ix,iy:外星人群的坐标(invaders_x,in-vaders_y) + idir:外星人群的移动方向(invaders_direc-tion) + laserwait:等离子炮弹的剩余充电时间 + movewait:当这个变量变为0时外星人群前进一步 + movewait0:movewait的初始值(消灭30只敌人后减少) + invline:外星人群的行数(invaders_line) + score:当前得分 + high:最高得分 + point:得分的增加量(奖金的单价?) + invstr:将外星人群的状态显示为字符串的变量 + */ + + int win, timer, i, j, fx, laserwait, lx = 0, ly; + int ix, iy, movewait0, movewait, idir; + int invline, score, high, point; + char winbuf[336 * 261], invstr[32 * 6], s[12], keyflag[4], *p; + static char invstr0[32] = " abcd abcd abcd abcd abcd "; + + win = api_openwin(winbuf, 336, 261, -1, "invader"); + api_boxfilwin(win, 6, 27, 329, 254, 0); + timer = api_alloctimer(); + api_inittimer(timer, 128); + + high = 0; + putstr(win, winbuf, 22, 0, 7, "HIGH:00000000"); + +restart: + score = 0; + point = 1; + putstr(win, winbuf, 4, 0, 7, "SCORE:00000000"); + movewait0 = 20; + fx = 18; + putstr(win, winbuf, fx, 13, 6, "efg"); + wait(100, timer, keyflag); + +next_group: + wait(100, timer, keyflag); + ix = 7; + iy = 1; + invline = 6; + for (i = 0; i < 6; i++) { + for (j = 0; j < 27; j++) { + invstr[i * 32 + j] = invstr0[j]; + } + putstr(win, winbuf, ix, iy + i, 2, invstr + i * 32); + } + keyflag[0] = 0; + keyflag[1] = 0; + keyflag[2] = 0; + + ly = 0; /*不显示*/ + laserwait = 0; + movewait = movewait0; + idir = +1; + wait(100, timer, keyflag); + + for (;;) { + if (laserwait != 0) { + laserwait--; + keyflag[2 /* space */] = 0; + } + + wait(4, timer, keyflag); + + /*自机的处理*/ + if (keyflag[0 /* left */] != 0 && fx > 0) { + fx--; + putstr(win, winbuf, fx, 13, 6, "efg "); + keyflag[0 /* left */] = 0; + } + if (keyflag[1 /* right */] != 0 && fx < 37) { + putstr(win, winbuf, fx, 13, 6, " efg"); + fx++; + keyflag[1 /* right */] = 0; + } + if (keyflag[2 /* space */] != 0 && laserwait == 0) { + laserwait = 15; + lx = fx + 1; + ly = 13; + } + + /*外星人移动*/ + if (movewait != 0) { + movewait--; + } else { + movewait = movewait0; + if (ix + idir > 14 || ix + idir < 0) { + if (iy + invline == 13) { + break; /* GAME OVER */ + } + idir = - idir; + putstr(win, winbuf, ix + 1, iy, 0, " "); + iy++; + } else { + ix += idir; + } + for (i = 0; i < invline; i++) { + putstr(win, winbuf, ix, iy + i, 2, invstr + i * 32); + } + } + + /*炮弹处理*/ + if (ly > 0) { + if (ly < 13) { + if (ix < lx && lx < ix + 25 && iy <= ly && ly < iy + invline) { + putstr(win, winbuf, ix, ly, 2, invstr + (ly - iy) * 32); + } else { + putstr(win, winbuf, lx, ly, 0, " "); + } + } + ly--; + if (ly > 0) { + putstr(win, winbuf, lx, ly, 3, "h"); + } else { + point -= 10; + if (point <= 0) { + point = 1; + } + } + if (ix < lx && lx < ix + 25 && iy <= ly && ly < iy + invline) { + p = invstr + (ly - iy) * 32 + (lx - ix); + if (*p != ' ') { + /* hit ! */ + score += point; + point++; + sprintf(s, "%08d", score); + putstr(win, winbuf, 10, 0, 7, s); + if (high < score) { + high = score; + putstr(win, winbuf, 27, 0, 7, s); + } + for (p--; *p != ' '; p--) { } + for (i = 1; i < 5; i++) { + p[i] = ' '; + } + putstr(win, winbuf, ix, ly, 2, invstr + (ly - iy) * 32); + for (; invline > 0; invline--) { + for (p = invstr + (invline - 1) * 32; *p != 0; p++) { + if (*p != ' ') { + goto alive; + } + } + } + /*全部消灭*/ + movewait0 -= movewait0 / 3; + goto next_group; + alive: + ly = 0; + } + } + } + } + + /* GAME OVER */ + putstr(win, winbuf, 15, 6, 1, "GAME OVER"); + wait(0, timer, keyflag); + for (i = 1; i < 14; i++) { + putstr(win, winbuf, 0, i, 0, " "); + } + goto restart; +} + +void putstr(int win, char *winbuf, int x, int y, int col, unsigned char *s) +{ + int c, x0, i; + char *p, *q, t[2]; + x = x * 8 + 8; + y = y * 16 + 29; + x0 = x; + i = strlen(s); /*计算s的字符数*/ + api_boxfilwin(win + 1, x, y, x + i * 8 - 1, y + 15, 0); + q = winbuf + y * 336; + t[1] = 0; + for (;;) { + c = *s; + if (c == 0) { + break; + } + if (c != ' ') { + if ('a' <= c && c <= 'h') { + p = charset + 16 * (c - 'a'); + q += x; + for (i = 0; i < 16; i++) { + if ((p[i] & 0x80) != 0) { q[0] = col; } + if ((p[i] & 0x40) != 0) { q[1] = col; } + if ((p[i] & 0x20) != 0) { q[2] = col; } + if ((p[i] & 0x10) != 0) { q[3] = col; } + if ((p[i] & 0x08) != 0) { q[4] = col; } + if ((p[i] & 0x04) != 0) { q[5] = col; } + if ((p[i] & 0x02) != 0) { q[6] = col; } + if ((p[i] & 0x01) != 0) { q[7] = col; } + q += 336; + } + q -= 336 * 16 + x; + } else { + t[0] = *s; + api_putstrwin(win + 1, x, y, col, 1, t); + } + } + s++; + x += 8; + } + api_refreshwin(win, x0, y, x, y + 16); + return; +} + +void wait(int i, int timer, char *keyflag) +{ + int j; + if (i > 0) { + /*等待一段时间*/ + api_settimer(timer, i); + i = 128; + } else { + i = 0x0a; /* Enter */ + } + for (;;) { + j = api_getkey(1); + if (i == j) { + break; + } + if (j == '4') { + keyflag[0 /* left */] = 1; + } + if (j == '6') { + keyflag[1 /* right */] = 1; + } + if (j == ' ') { + keyflag[2 /* space */] = 1; + } + } + return; +} diff --git a/29_day/invader/make.bat b/29_day/invader/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/29_day/invader/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file From 2c262f986d9ed842c08e243781716b7d47f39ed6 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 20 May 2016 10:44:09 +0800 Subject: [PATCH 62/83] Add 30 day code --- 30_day/!cons_9x.bat | 1 + 30_day/!cons_nt.bat | 1 + 30_day/Makefile | 183 ++ 30_day/a/!cons_9x.bat | 1 + 30_day/a/!cons_nt.bat | 1 + 30_day/a/Makefile | 5 + 30_day/a/a.c | 7 + 30_day/a/make.bat | 1 + 30_day/apilib.h | 27 + 30_day/apilib/!cons_9x.bat | 1 + 30_day/apilib/!cons_nt.bat | 1 + 30_day/apilib/Makefile | 48 + 30_day/apilib/alloca.nas | 13 + 30_day/apilib/api001.nas | 14 + 30_day/apilib/api002.nas | 16 + 30_day/apilib/api003.nas | 17 + 30_day/apilib/api004.nas | 12 + 30_day/apilib/api005.nas | 24 + 30_day/apilib/api006.nas | 27 + 30_day/apilib/api007.nas | 27 + 30_day/apilib/api008.nas | 20 + 30_day/apilib/api009.nas | 17 + 30_day/apilib/api010.nas | 18 + 30_day/apilib/api011.nas | 23 + 30_day/apilib/api012.nas | 24 + 30_day/apilib/api013.nas | 27 + 30_day/apilib/api014.nas | 16 + 30_day/apilib/api015.nas | 14 + 30_day/apilib/api016.nas | 13 + 30_day/apilib/api017.nas | 17 + 30_day/apilib/api018.nas | 17 + 30_day/apilib/api019.nas | 16 + 30_day/apilib/api020.nas | 14 + 30_day/apilib/api021.nas | 16 + 30_day/apilib/api022.nas | 14 + 30_day/apilib/api023.nas | 18 + 30_day/apilib/api024.nas | 15 + 30_day/apilib/api025.nas | 18 + 30_day/apilib/api026.nas | 17 + 30_day/apilib/api027.nas | 13 + 30_day/apilib/apilib.lib | Bin 0 -> 8966 bytes 30_day/apilib/make.bat | 1 + 30_day/app_make.txt | 92 + 30_day/bball/!cons_9x.bat | 1 + 30_day/bball/!cons_nt.bat | 1 + 30_day/bball/Makefile | 5 + 30_day/bball/bball.c | 37 + 30_day/bball/make.bat | 1 + 30_day/beepdown/!cons_9x.bat | 1 + 30_day/beepdown/!cons_nt.bat | 1 + 30_day/beepdown/Makefile | 5 + 30_day/beepdown/beepdown.c | 19 + 30_day/beepdown/make.bat | 1 + 30_day/chklang/!cons_9x.bat | 1 + 30_day/chklang/!cons_nt.bat | 1 + 30_day/chklang/Makefile | 5 + 30_day/chklang/chklang.c | 24 + 30_day/chklang/make.bat | 1 + 30_day/color/!cons_9x.bat | 1 + 30_day/color/!cons_nt.bat | 1 + 30_day/color/Makefile | 5 + 30_day/color/color.c | 21 + 30_day/color/make.bat | 1 + 30_day/color2/!cons_9x.bat | 1 + 30_day/color2/!cons_nt.bat | 1 + 30_day/color2/Makefile | 5 + 30_day/color2/color2.c | 36 + 30_day/color2/make.bat | 1 + 30_day/euc.txt | 1 + 30_day/haribote.rul | 10 + 30_day/haribote/!cons_9x.bat | 1 + 30_day/haribote/!cons_nt.bat | 1 + 30_day/haribote/Makefile | 79 + 30_day/haribote/asmhead.nas | 202 ++ 30_day/haribote/bootpack.c | 412 +++ 30_day/haribote/bootpack.h | 297 +++ 30_day/haribote/console.c | 708 ++++++ 30_day/haribote/dsctbl.c | 59 + 30_day/haribote/fifo.c | 63 + 30_day/haribote/file.c | 94 + 30_day/haribote/graphic.c | 221 ++ 30_day/haribote/hankaku.txt | 4609 ++++++++++++++++++++++++++++++++++ 30_day/haribote/haribote.sys | Bin 0 -> 33331 bytes 30_day/haribote/int.c | 26 + 30_day/haribote/ipl20.nas | 109 + 30_day/haribote/jp.nas | 107 + 30_day/haribote/keyboard.c | 44 + 30_day/haribote/make.bat | 1 + 30_day/haribote/memory.c | 162 ++ 30_day/haribote/mouse.c | 76 + 30_day/haribote/mtask.c | 203 ++ 30_day/haribote/naskfunc.nas | 291 +++ 30_day/haribote/sheet.c | 294 +++ 30_day/haribote/tek.c | 646 +++++ 30_day/haribote/timer.c | 169 ++ 30_day/haribote/window.c | 124 + 30_day/hello3/!cons_9x.bat | 1 + 30_day/hello3/!cons_nt.bat | 1 + 30_day/hello3/Makefile | 5 + 30_day/hello3/hello3.c | 11 + 30_day/hello3/make.bat | 1 + 30_day/hello4/!cons_9x.bat | 1 + 30_day/hello4/!cons_nt.bat | 1 + 30_day/hello4/Makefile | 8 + 30_day/hello4/hello4.c | 7 + 30_day/hello4/make.bat | 1 + 30_day/hello5/!cons_9x.bat | 1 + 30_day/hello5/!cons_nt.bat | 1 + 30_day/hello5/Makefile | 8 + 30_day/hello5/hello5.nas | 20 + 30_day/hello5/make.bat | 1 + 30_day/invader/!cons_9x.bat | 1 + 30_day/invader/!cons_nt.bat | 1 + 30_day/invader/Makefile | 5 + 30_day/invader/invader.c | 281 +++ 30_day/invader/make.bat | 1 + 30_day/iroha/!cons_9x.bat | 1 + 30_day/iroha/!cons_nt.bat | 1 + 30_day/iroha/Makefile | 5 + 30_day/iroha/iroha.c | 9 + 30_day/iroha/make.bat | 1 + 30_day/lines/!cons_9x.bat | 1 + 30_day/lines/!cons_nt.bat | 1 + 30_day/lines/Makefile | 5 + 30_day/lines/lines.c | 22 + 30_day/lines/make.bat | 1 + 30_day/make.bat | 1 + 30_day/nihongo/jpn16v00.bin | Bin 0 -> 311296 bytes 30_day/nihongo/jpn16v00.fnt | Bin 0 -> 58084 bytes 30_day/nihongo/nihongo.fnt | Bin 0 -> 58009 bytes 30_day/nihongo/nihongo.org | Bin 0 -> 145472 bytes 30_day/noodle/!cons_9x.bat | 1 + 30_day/noodle/!cons_nt.bat | 1 + 30_day/noodle/Makefile | 5 + 30_day/noodle/make.bat | 1 + 30_day/noodle/noodle.c | 32 + 30_day/notrec/!cons_9x.bat | 1 + 30_day/notrec/!cons_nt.bat | 1 + 30_day/notrec/Makefile | 5 + 30_day/notrec/make.bat | 1 + 30_day/notrec/notrec.c | 17 + 30_day/sosu/!cons_9x.bat | 1 + 30_day/sosu/!cons_nt.bat | 1 + 30_day/sosu/Makefile | 5 + 30_day/sosu/make.bat | 1 + 30_day/sosu/sosu.c | 24 + 30_day/sosu2/!cons_9x.bat | 1 + 30_day/sosu2/!cons_nt.bat | 1 + 30_day/sosu2/Makefile | 5 + 30_day/sosu2/make.bat | 1 + 30_day/sosu2/sosu2.c | 24 + 30_day/sosu3/!cons_9x.bat | 1 + 30_day/sosu3/!cons_nt.bat | 1 + 30_day/sosu3/Makefile | 5 + 30_day/sosu3/make.bat | 1 + 30_day/sosu3/sosu3.c | 26 + 30_day/star1/!cons_9x.bat | 1 + 30_day/star1/!cons_nt.bat | 1 + 30_day/star1/Makefile | 5 + 30_day/star1/make.bat | 1 + 30_day/star1/star1.c | 18 + 30_day/stars/!cons_9x.bat | 1 + 30_day/stars/!cons_nt.bat | 1 + 30_day/stars/Makefile | 5 + 30_day/stars/make.bat | 1 + 30_day/stars/stars.c | 24 + 30_day/stars2/!cons_9x.bat | 1 + 30_day/stars2/!cons_nt.bat | 1 + 30_day/stars2/Makefile | 5 + 30_day/stars2/make.bat | 1 + 30_day/stars2/stars2.c | 25 + 30_day/stdlib.h | 4 + 30_day/stdlib/!cons_9x.bat | 1 + 30_day/stdlib/!cons_nt.bat | 1 + 30_day/stdlib/Makefile | 50 + 30_day/stdlib/make.bat | 1 + 30_day/stdlib/stdlib.c | 51 + 30_day/tek/autodec_.c | 649 +++++ 30_day/tek/tek.c | 646 +++++ 30_day/type/!cons_9x.bat | 1 + 30_day/type/!cons_nt.bat | 1 + 30_day/type/Makefile | 5 + 30_day/type/make.bat | 1 + 30_day/type/type.c | 23 + 30_day/walk/!cons_9x.bat | 1 + 30_day/walk/!cons_nt.bat | 1 + 30_day/walk/Makefile | 5 + 30_day/walk/make.bat | 1 + 30_day/walk/walk.c | 26 + 30_day/winhelo/!cons_9x.bat | 1 + 30_day/winhelo/!cons_nt.bat | 1 + 30_day/winhelo/Makefile | 9 + 30_day/winhelo/make.bat | 1 + 30_day/winhelo/winhelo.c | 15 + 30_day/winhelo2/!cons_9x.bat | 1 + 30_day/winhelo2/!cons_nt.bat | 1 + 30_day/winhelo2/Makefile | 5 + 30_day/winhelo2/make.bat | 1 + 30_day/winhelo2/winhelo2.c | 17 + 30_day/winhelo3/!cons_9x.bat | 1 + 30_day/winhelo3/!cons_nt.bat | 1 + 30_day/winhelo3/Makefile | 5 + 30_day/winhelo3/make.bat | 1 + 30_day/winhelo3/winhelo3.c | 19 + 204 files changed, 12259 insertions(+) create mode 100644 30_day/!cons_9x.bat create mode 100644 30_day/!cons_nt.bat create mode 100644 30_day/Makefile create mode 100644 30_day/a/!cons_9x.bat create mode 100644 30_day/a/!cons_nt.bat create mode 100644 30_day/a/Makefile create mode 100644 30_day/a/a.c create mode 100644 30_day/a/make.bat create mode 100644 30_day/apilib.h create mode 100644 30_day/apilib/!cons_9x.bat create mode 100644 30_day/apilib/!cons_nt.bat create mode 100644 30_day/apilib/Makefile create mode 100644 30_day/apilib/alloca.nas create mode 100644 30_day/apilib/api001.nas create mode 100644 30_day/apilib/api002.nas create mode 100644 30_day/apilib/api003.nas create mode 100644 30_day/apilib/api004.nas create mode 100644 30_day/apilib/api005.nas create mode 100644 30_day/apilib/api006.nas create mode 100644 30_day/apilib/api007.nas create mode 100644 30_day/apilib/api008.nas create mode 100644 30_day/apilib/api009.nas create mode 100644 30_day/apilib/api010.nas create mode 100644 30_day/apilib/api011.nas create mode 100644 30_day/apilib/api012.nas create mode 100644 30_day/apilib/api013.nas create mode 100644 30_day/apilib/api014.nas create mode 100644 30_day/apilib/api015.nas create mode 100644 30_day/apilib/api016.nas create mode 100644 30_day/apilib/api017.nas create mode 100644 30_day/apilib/api018.nas create mode 100644 30_day/apilib/api019.nas create mode 100644 30_day/apilib/api020.nas create mode 100644 30_day/apilib/api021.nas create mode 100644 30_day/apilib/api022.nas create mode 100644 30_day/apilib/api023.nas create mode 100644 30_day/apilib/api024.nas create mode 100644 30_day/apilib/api025.nas create mode 100644 30_day/apilib/api026.nas create mode 100644 30_day/apilib/api027.nas create mode 100644 30_day/apilib/apilib.lib create mode 100644 30_day/apilib/make.bat create mode 100644 30_day/app_make.txt create mode 100644 30_day/bball/!cons_9x.bat create mode 100644 30_day/bball/!cons_nt.bat create mode 100644 30_day/bball/Makefile create mode 100644 30_day/bball/bball.c create mode 100644 30_day/bball/make.bat create mode 100644 30_day/beepdown/!cons_9x.bat create mode 100644 30_day/beepdown/!cons_nt.bat create mode 100644 30_day/beepdown/Makefile create mode 100644 30_day/beepdown/beepdown.c create mode 100644 30_day/beepdown/make.bat create mode 100644 30_day/chklang/!cons_9x.bat create mode 100644 30_day/chklang/!cons_nt.bat create mode 100644 30_day/chklang/Makefile create mode 100644 30_day/chklang/chklang.c create mode 100644 30_day/chklang/make.bat create mode 100644 30_day/color/!cons_9x.bat create mode 100644 30_day/color/!cons_nt.bat create mode 100644 30_day/color/Makefile create mode 100644 30_day/color/color.c create mode 100644 30_day/color/make.bat create mode 100644 30_day/color2/!cons_9x.bat create mode 100644 30_day/color2/!cons_nt.bat create mode 100644 30_day/color2/Makefile create mode 100644 30_day/color2/color2.c create mode 100644 30_day/color2/make.bat create mode 100644 30_day/euc.txt create mode 100644 30_day/haribote.rul create mode 100644 30_day/haribote/!cons_9x.bat create mode 100644 30_day/haribote/!cons_nt.bat create mode 100644 30_day/haribote/Makefile create mode 100644 30_day/haribote/asmhead.nas create mode 100644 30_day/haribote/bootpack.c create mode 100644 30_day/haribote/bootpack.h create mode 100644 30_day/haribote/console.c create mode 100644 30_day/haribote/dsctbl.c create mode 100644 30_day/haribote/fifo.c create mode 100644 30_day/haribote/file.c create mode 100644 30_day/haribote/graphic.c create mode 100644 30_day/haribote/hankaku.txt create mode 100644 30_day/haribote/haribote.sys create mode 100644 30_day/haribote/int.c create mode 100644 30_day/haribote/ipl20.nas create mode 100644 30_day/haribote/jp.nas create mode 100644 30_day/haribote/keyboard.c create mode 100644 30_day/haribote/make.bat create mode 100644 30_day/haribote/memory.c create mode 100644 30_day/haribote/mouse.c create mode 100644 30_day/haribote/mtask.c create mode 100644 30_day/haribote/naskfunc.nas create mode 100644 30_day/haribote/sheet.c create mode 100644 30_day/haribote/tek.c create mode 100644 30_day/haribote/timer.c create mode 100644 30_day/haribote/window.c create mode 100644 30_day/hello3/!cons_9x.bat create mode 100644 30_day/hello3/!cons_nt.bat create mode 100644 30_day/hello3/Makefile create mode 100644 30_day/hello3/hello3.c create mode 100644 30_day/hello3/make.bat create mode 100644 30_day/hello4/!cons_9x.bat create mode 100644 30_day/hello4/!cons_nt.bat create mode 100644 30_day/hello4/Makefile create mode 100644 30_day/hello4/hello4.c create mode 100644 30_day/hello4/make.bat create mode 100644 30_day/hello5/!cons_9x.bat create mode 100644 30_day/hello5/!cons_nt.bat create mode 100644 30_day/hello5/Makefile create mode 100644 30_day/hello5/hello5.nas create mode 100644 30_day/hello5/make.bat create mode 100644 30_day/invader/!cons_9x.bat create mode 100644 30_day/invader/!cons_nt.bat create mode 100644 30_day/invader/Makefile create mode 100644 30_day/invader/invader.c create mode 100644 30_day/invader/make.bat create mode 100644 30_day/iroha/!cons_9x.bat create mode 100644 30_day/iroha/!cons_nt.bat create mode 100644 30_day/iroha/Makefile create mode 100644 30_day/iroha/iroha.c create mode 100644 30_day/iroha/make.bat create mode 100644 30_day/lines/!cons_9x.bat create mode 100644 30_day/lines/!cons_nt.bat create mode 100644 30_day/lines/Makefile create mode 100644 30_day/lines/lines.c create mode 100644 30_day/lines/make.bat create mode 100644 30_day/make.bat create mode 100644 30_day/nihongo/jpn16v00.bin create mode 100644 30_day/nihongo/jpn16v00.fnt create mode 100644 30_day/nihongo/nihongo.fnt create mode 100644 30_day/nihongo/nihongo.org create mode 100644 30_day/noodle/!cons_9x.bat create mode 100644 30_day/noodle/!cons_nt.bat create mode 100644 30_day/noodle/Makefile create mode 100644 30_day/noodle/make.bat create mode 100644 30_day/noodle/noodle.c create mode 100644 30_day/notrec/!cons_9x.bat create mode 100644 30_day/notrec/!cons_nt.bat create mode 100644 30_day/notrec/Makefile create mode 100644 30_day/notrec/make.bat create mode 100644 30_day/notrec/notrec.c create mode 100644 30_day/sosu/!cons_9x.bat create mode 100644 30_day/sosu/!cons_nt.bat create mode 100644 30_day/sosu/Makefile create mode 100644 30_day/sosu/make.bat create mode 100644 30_day/sosu/sosu.c create mode 100644 30_day/sosu2/!cons_9x.bat create mode 100644 30_day/sosu2/!cons_nt.bat create mode 100644 30_day/sosu2/Makefile create mode 100644 30_day/sosu2/make.bat create mode 100644 30_day/sosu2/sosu2.c create mode 100644 30_day/sosu3/!cons_9x.bat create mode 100644 30_day/sosu3/!cons_nt.bat create mode 100644 30_day/sosu3/Makefile create mode 100644 30_day/sosu3/make.bat create mode 100644 30_day/sosu3/sosu3.c create mode 100644 30_day/star1/!cons_9x.bat create mode 100644 30_day/star1/!cons_nt.bat create mode 100644 30_day/star1/Makefile create mode 100644 30_day/star1/make.bat create mode 100644 30_day/star1/star1.c create mode 100644 30_day/stars/!cons_9x.bat create mode 100644 30_day/stars/!cons_nt.bat create mode 100644 30_day/stars/Makefile create mode 100644 30_day/stars/make.bat create mode 100644 30_day/stars/stars.c create mode 100644 30_day/stars2/!cons_9x.bat create mode 100644 30_day/stars2/!cons_nt.bat create mode 100644 30_day/stars2/Makefile create mode 100644 30_day/stars2/make.bat create mode 100644 30_day/stars2/stars2.c create mode 100644 30_day/stdlib.h create mode 100644 30_day/stdlib/!cons_9x.bat create mode 100644 30_day/stdlib/!cons_nt.bat create mode 100644 30_day/stdlib/Makefile create mode 100644 30_day/stdlib/make.bat create mode 100644 30_day/stdlib/stdlib.c create mode 100644 30_day/tek/autodec_.c create mode 100644 30_day/tek/tek.c create mode 100644 30_day/type/!cons_9x.bat create mode 100644 30_day/type/!cons_nt.bat create mode 100644 30_day/type/Makefile create mode 100644 30_day/type/make.bat create mode 100644 30_day/type/type.c create mode 100644 30_day/walk/!cons_9x.bat create mode 100644 30_day/walk/!cons_nt.bat create mode 100644 30_day/walk/Makefile create mode 100644 30_day/walk/make.bat create mode 100644 30_day/walk/walk.c create mode 100644 30_day/winhelo/!cons_9x.bat create mode 100644 30_day/winhelo/!cons_nt.bat create mode 100644 30_day/winhelo/Makefile create mode 100644 30_day/winhelo/make.bat create mode 100644 30_day/winhelo/winhelo.c create mode 100644 30_day/winhelo2/!cons_9x.bat create mode 100644 30_day/winhelo2/!cons_nt.bat create mode 100644 30_day/winhelo2/Makefile create mode 100644 30_day/winhelo2/make.bat create mode 100644 30_day/winhelo2/winhelo2.c create mode 100644 30_day/winhelo3/!cons_9x.bat create mode 100644 30_day/winhelo3/!cons_nt.bat create mode 100644 30_day/winhelo3/Makefile create mode 100644 30_day/winhelo3/make.bat create mode 100644 30_day/winhelo3/winhelo3.c diff --git a/30_day/!cons_9x.bat b/30_day/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/!cons_nt.bat b/30_day/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/Makefile b/30_day/Makefile new file mode 100644 index 0000000..f92b3d5 --- /dev/null +++ b/30_day/Makefile @@ -0,0 +1,183 @@ +TOOLPATH = ../z_tools/ +INCPATH = ../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) haribote.img + +#文件生成规则 + +haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ + a/a.hrb hello3/hello3.hrb hello4/hello4.hrb hello5/hello5.hrb \ + winhelo/winhelo.hrb winhelo2/winhelo2.hrb winhelo3/winhelo3.hrb \ + star1/star1.hrb stars/stars.hrb stars2/stars2.hrb \ + lines/lines.hrb walk/walk.hrb noodle/noodle.hrb \ + beepdown/beepdown.hrb color/color.hrb color2/color2.hrb \ + sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb \ + type/type.hrb iroha/iroha.hrb chklang/chklang.hrb \ + notrec/notrec.hrb bball/bball.hrb invader/invader.hrb + $(EDIMG) imgin:../z_tools/fdimg0at.tek \ + wbinimg src:haribote/ipl20.bin len:512 from:0 to:0 \ + copy from:haribote/haribote.sys to:@: \ + copy from:haribote/jp.nas to:@: \ + copy from:make.bat to:@: \ + copy from:a/a.hrb to:@: \ + copy from:hello3/hello3.hrb to:@: \ + copy from:hello4/hello4.hrb to:@: \ + copy from:hello5/hello5.hrb to:@: \ + copy from:winhelo/winhelo.hrb to:@: \ + copy from:winhelo2/winhelo2.hrb to:@: \ + copy from:winhelo3/winhelo3.hrb to:@: \ + copy from:star1/star1.hrb to:@: \ + copy from:stars/stars.hrb to:@: \ + copy from:stars2/stars2.hrb to:@: \ + copy from:lines/lines.hrb to:@: \ + copy from:walk/walk.hrb to:@: \ + copy from:noodle/noodle.hrb to:@: \ + copy from:beepdown/beepdown.hrb to:@: \ + copy from:color/color.hrb to:@: \ + copy from:color2/color2.hrb to:@: \ + copy from:sosu/sosu.hrb to:@: \ + copy from:sosu2/sosu2.hrb to:@: \ + copy from:sosu3/sosu3.hrb to:@: \ + copy from:type/type.hrb to:@: \ + copy from:iroha/iroha.hrb to:@: \ + copy from:chklang/chklang.hrb to:@: \ + copy from:euc.txt to:@: \ + copy from:notrec/notrec.hrb to:@: \ + copy from:bball/bball.hrb to:@: \ + copy from:invader/invader.hrb to:@: \ + copy from:nihongo/nihongo.fnt to:@: \ + imgout:haribote.img + +#命令 + +run : + $(MAKE) haribote.img + $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../z_tools/qemu + +install : + $(MAKE) haribote.img + $(IMGTOL) w a: haribote.img + +full : + $(MAKE) -C haribote + $(MAKE) -C apilib + $(MAKE) -C a + $(MAKE) -C hello3 + $(MAKE) -C hello4 + $(MAKE) -C hello5 + $(MAKE) -C winhelo + $(MAKE) -C winhelo2 + $(MAKE) -C winhelo3 + $(MAKE) -C star1 + $(MAKE) -C stars + $(MAKE) -C stars2 + $(MAKE) -C lines + $(MAKE) -C walk + $(MAKE) -C noodle + $(MAKE) -C beepdown + $(MAKE) -C color + $(MAKE) -C color2 + $(MAKE) -C sosu + $(MAKE) -C sosu2 + $(MAKE) -C sosu3 + $(MAKE) -C type + $(MAKE) -C iroha + $(MAKE) -C chklang + $(MAKE) -C notrec + $(MAKE) -C bball + $(MAKE) -C invader + $(MAKE) haribote.img + +run_full : + $(MAKE) full + $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../z_tools/qemu + +install_full : + $(MAKE) full + $(IMGTOL) w a: haribote.img + +run_os : + $(MAKE) -C haribote + $(MAKE) run + +clean : +#不执行任何操作 + +src_only : + $(MAKE) clean + -$(DEL) haribote.img + +clean_full : + $(MAKE) -C haribote clean + $(MAKE) -C apilib clean + $(MAKE) -C a clean + $(MAKE) -C hello3 clean + $(MAKE) -C hello4 clean + $(MAKE) -C hello5 clean + $(MAKE) -C winhelo clean + $(MAKE) -C winhelo2 clean + $(MAKE) -C winhelo3 clean + $(MAKE) -C star1 clean + $(MAKE) -C stars clean + $(MAKE) -C stars2 clean + $(MAKE) -C lines clean + $(MAKE) -C walk clean + $(MAKE) -C noodle clean + $(MAKE) -C beepdown clean + $(MAKE) -C color clean + $(MAKE) -C color2 clean + $(MAKE) -C sosu clean + $(MAKE) -C sosu2 clean + $(MAKE) -C sosu3 clean + $(MAKE) -C type clean + $(MAKE) -C iroha clean + $(MAKE) -C chklang clean + $(MAKE) -C notrec clean + $(MAKE) -C bball clean + $(MAKE) -C invader clean + +src_only_full : + $(MAKE) -C haribote src_only + $(MAKE) -C apilib src_only + $(MAKE) -C a src_only + $(MAKE) -C hello3 src_only + $(MAKE) -C hello4 src_only + $(MAKE) -C hello5 src_only + $(MAKE) -C winhelo src_only + $(MAKE) -C winhelo2 src_only + $(MAKE) -C winhelo3 src_only + $(MAKE) -C star1 src_only + $(MAKE) -C stars src_only + $(MAKE) -C stars2 src_only + $(MAKE) -C lines src_only + $(MAKE) -C walk src_only + $(MAKE) -C noodle src_only + $(MAKE) -C beepdown src_only + $(MAKE) -C color src_only + $(MAKE) -C color2 src_only + $(MAKE) -C sosu src_only + $(MAKE) -C sosu2 src_only + $(MAKE) -C sosu3 src_only + $(MAKE) -C type src_only + $(MAKE) -C iroha src_only + $(MAKE) -C chklang src_only + $(MAKE) -C notrec src_only + $(MAKE) -C bball src_only + $(MAKE) -C invader src_only + -$(DEL) haribote.img + +refresh : + $(MAKE) full + $(MAKE) clean_full + -$(DEL) haribote.img diff --git a/30_day/a/!cons_9x.bat b/30_day/a/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/a/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/a/!cons_nt.bat b/30_day/a/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/a/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/a/Makefile b/30_day/a/Makefile new file mode 100644 index 0000000..674a683 --- /dev/null +++ b/30_day/a/Makefile @@ -0,0 +1,5 @@ +APP = a +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/a/a.c b/30_day/a/a.c new file mode 100644 index 0000000..3df81f5 --- /dev/null +++ b/30_day/a/a.c @@ -0,0 +1,7 @@ +#include "apilib.h" + +void HariMain(void) +{ + api_putchar('A'); + api_end(); +} diff --git a/30_day/a/make.bat b/30_day/a/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/a/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/apilib.h b/30_day/apilib.h new file mode 100644 index 0000000..ac282d8 --- /dev/null +++ b/30_day/apilib.h @@ -0,0 +1,27 @@ +void api_putchar(int c); +void api_putstr0(char *s); +void api_putstr1(char *s, int l); +void api_end(void); +int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); +void api_putstrwin(int win, int x, int y, int col, int len, char *str); +void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); +void api_initmalloc(void); +char *api_malloc(int size); +void api_free(char *addr, int size); +void api_point(int win, int x, int y, int col); +void api_refreshwin(int win, int x0, int y0, int x1, int y1); +void api_linewin(int win, int x0, int y0, int x1, int y1, int col); +void api_closewin(int win); +int api_getkey(int mode); +int api_alloctimer(void); +void api_inittimer(int timer, int data); +void api_settimer(int timer, int time); +void api_freetimer(int timer); +void api_beep(int tone); +int api_fopen(char *fname); +void api_fclose(int fhandle); +void api_fseek(int fhandle, int offset, int mode); +int api_fsize(int fhandle, int mode); +int api_fread(char *buf, int maxsize, int fhandle); +int api_cmdline(char *buf, int maxsize); +int api_getlang(void); diff --git a/30_day/apilib/!cons_9x.bat b/30_day/apilib/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/apilib/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/apilib/!cons_nt.bat b/30_day/apilib/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/apilib/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/apilib/Makefile b/30_day/apilib/Makefile new file mode 100644 index 0000000..8ce9ef5 --- /dev/null +++ b/30_day/apilib/Makefile @@ -0,0 +1,48 @@ +OBJS_API = api001.obj api002.obj api003.obj api004.obj api005.obj api006.obj \ + api007.obj api008.obj api009.obj api010.obj api011.obj api012.obj \ + api013.obj api014.obj api015.obj api016.obj api017.obj api018.obj \ + api019.obj api020.obj api021.obj api022.obj api023.obj api024.obj \ + api025.obj api026.obj api027.obj alloca.obj + +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) apilib.lib + +#库生成规则 + +apilib.lib : Makefile $(OBJS_API) + $(GOLIB) $(OBJS_API) out:apilib.lib + +#文件生成规则 + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +#命令 + +clean : + -$(DEL) *.lst + -$(DEL) *.obj + +src_only : + $(MAKE) clean + -$(DEL) apilib.lib diff --git a/30_day/apilib/alloca.nas b/30_day/apilib/alloca.nas new file mode 100644 index 0000000..b94f8e2 --- /dev/null +++ b/30_day/apilib/alloca.nas @@ -0,0 +1,13 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "alloca.nas"] + + GLOBAL __alloca + +[SECTION .text] + +__alloca: + ADD EAX,-4 + SUB ESP,EAX + JMP DWORD [ESP+EAX] ; 代替RET diff --git a/30_day/apilib/api001.nas b/30_day/apilib/api001.nas new file mode 100644 index 0000000..2f893a9 --- /dev/null +++ b/30_day/apilib/api001.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api001.nas"] + + GLOBAL _api_putchar + +[SECTION .text] + +_api_putchar: ; void api_putchar(int c); + MOV EDX,1 + MOV AL,[ESP+4] ; c + INT 0x40 + RET diff --git a/30_day/apilib/api002.nas b/30_day/apilib/api002.nas new file mode 100644 index 0000000..6ac9cc7 --- /dev/null +++ b/30_day/apilib/api002.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api002.nas"] + + GLOBAL _api_putstr0 + +[SECTION .text] + +_api_putstr0: ; void api_putstr0(char *s); + PUSH EBX + MOV EDX,2 + MOV EBX,[ESP+8] ; s + INT 0x40 + POP EBX + RET diff --git a/30_day/apilib/api003.nas b/30_day/apilib/api003.nas new file mode 100644 index 0000000..6c2d0fd --- /dev/null +++ b/30_day/apilib/api003.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api003.nas"] + + GLOBAL _api_putstr1 + +[SECTION .text] + +_api_putstr1: ; void api_putstr1(char *s, int l); + PUSH EBX + MOV EDX,3 + MOV EBX,[ESP+ 8] ; s + MOV ECX,[ESP+12] ; l + INT 0x40 + POP EBX + RET diff --git a/30_day/apilib/api004.nas b/30_day/apilib/api004.nas new file mode 100644 index 0000000..3c738a3 --- /dev/null +++ b/30_day/apilib/api004.nas @@ -0,0 +1,12 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api004.nas"] + + GLOBAL _api_end + +[SECTION .text] + +_api_end: ; void api_end(void); + MOV EDX,4 + INT 0x40 diff --git a/30_day/apilib/api005.nas b/30_day/apilib/api005.nas new file mode 100644 index 0000000..2157c61 --- /dev/null +++ b/30_day/apilib/api005.nas @@ -0,0 +1,24 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api005.nas"] + + GLOBAL _api_openwin + +[SECTION .text] + +_api_openwin: ; int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,5 + MOV EBX,[ESP+16] ; buf + MOV ESI,[ESP+20] ; xsiz + MOV EDI,[ESP+24] ; ysiz + MOV EAX,[ESP+28] ; col_inv + MOV ECX,[ESP+32] ; title + INT 0x40 + POP EBX + POP ESI + POP EDI + RET diff --git a/30_day/apilib/api006.nas b/30_day/apilib/api006.nas new file mode 100644 index 0000000..94cbb2d --- /dev/null +++ b/30_day/apilib/api006.nas @@ -0,0 +1,27 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api006.nas"] + + GLOBAL _api_putstrwin + +[SECTION .text] + +_api_putstrwin: ; void api_putstrwin(int win, int x, int y, int col, int len, char *str); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,6 + MOV EBX,[ESP+20] ; win + MOV ESI,[ESP+24] ; x + MOV EDI,[ESP+28] ; y + MOV EAX,[ESP+32] ; col + MOV ECX,[ESP+36] ; len + MOV EBP,[ESP+40] ; str + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET diff --git a/30_day/apilib/api007.nas b/30_day/apilib/api007.nas new file mode 100644 index 0000000..57be736 --- /dev/null +++ b/30_day/apilib/api007.nas @@ -0,0 +1,27 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api007.nas"] + + GLOBAL _api_boxfilwin + +[SECTION .text] + +_api_boxfilwin: ; void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,7 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET diff --git a/30_day/apilib/api008.nas b/30_day/apilib/api008.nas new file mode 100644 index 0000000..d1ed6c7 --- /dev/null +++ b/30_day/apilib/api008.nas @@ -0,0 +1,20 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api008.nas"] + + GLOBAL _api_initmalloc + +[SECTION .text] + +_api_initmalloc: ; void api_initmalloc(void); + PUSH EBX + MOV EDX,8 + MOV EBX,[CS:0x0020] ; malloc内存空间的地址 + MOV EAX,EBX + ADD EAX,32*1024 ; 加上32KB + MOV ECX,[CS:0x0000] ; 数据段的大小 + SUB ECX,EAX + INT 0x40 + POP EBX + RET diff --git a/30_day/apilib/api009.nas b/30_day/apilib/api009.nas new file mode 100644 index 0000000..bcd5307 --- /dev/null +++ b/30_day/apilib/api009.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api009.nas"] + + GLOBAL _api_malloc + +[SECTION .text] + +_api_malloc: ; char *api_malloc(int size); + PUSH EBX + MOV EDX,9 + MOV EBX,[CS:0x0020] + MOV ECX,[ESP+8] ; size + INT 0x40 + POP EBX + RET diff --git a/30_day/apilib/api010.nas b/30_day/apilib/api010.nas new file mode 100644 index 0000000..63a4ea5 --- /dev/null +++ b/30_day/apilib/api010.nas @@ -0,0 +1,18 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api010.nas"] + + GLOBAL _api_free + +[SECTION .text] + +_api_free: ; void api_free(char *addr, int size); + PUSH EBX + MOV EDX,10 + MOV EBX,[CS:0x0020] + MOV EAX,[ESP+ 8] ; addr + MOV ECX,[ESP+12] ; size + INT 0x40 + POP EBX + RET diff --git a/30_day/apilib/api011.nas b/30_day/apilib/api011.nas new file mode 100644 index 0000000..f5994b9 --- /dev/null +++ b/30_day/apilib/api011.nas @@ -0,0 +1,23 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api011.nas"] + + GLOBAL _api_point + +[SECTION .text] + +_api_point: ; void api_point(int win, int x, int y, int col); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,11 + MOV EBX,[ESP+16] ; win + MOV ESI,[ESP+20] ; x + MOV EDI,[ESP+24] ; y + MOV EAX,[ESP+28] ; col + INT 0x40 + POP EBX + POP ESI + POP EDI + RET diff --git a/30_day/apilib/api012.nas b/30_day/apilib/api012.nas new file mode 100644 index 0000000..9e9386f --- /dev/null +++ b/30_day/apilib/api012.nas @@ -0,0 +1,24 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api012.nas"] + + GLOBAL _api_refreshwin + +[SECTION .text] + +_api_refreshwin: ; void api_refreshwin(int win, int x0, int y0, int x1, int y1); + PUSH EDI + PUSH ESI + PUSH EBX + MOV EDX,12 + MOV EBX,[ESP+16] ; win + MOV EAX,[ESP+20] ; x0 + MOV ECX,[ESP+24] ; y0 + MOV ESI,[ESP+28] ; x1 + MOV EDI,[ESP+32] ; y1 + INT 0x40 + POP EBX + POP ESI + POP EDI + RET diff --git a/30_day/apilib/api013.nas b/30_day/apilib/api013.nas new file mode 100644 index 0000000..017f1ea --- /dev/null +++ b/30_day/apilib/api013.nas @@ -0,0 +1,27 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api013.nas"] + + GLOBAL _api_linewin + +[SECTION .text] + +_api_linewin: ; void api_linewin(int win, int x0, int y0, int x1, int y1, int col); + PUSH EDI + PUSH ESI + PUSH EBP + PUSH EBX + MOV EDX,13 + MOV EBX,[ESP+20] ; win + MOV EAX,[ESP+24] ; x0 + MOV ECX,[ESP+28] ; y0 + MOV ESI,[ESP+32] ; x1 + MOV EDI,[ESP+36] ; y1 + MOV EBP,[ESP+40] ; col + INT 0x40 + POP EBX + POP EBP + POP ESI + POP EDI + RET diff --git a/30_day/apilib/api014.nas b/30_day/apilib/api014.nas new file mode 100644 index 0000000..363db51 --- /dev/null +++ b/30_day/apilib/api014.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api014.nas"] + + GLOBAL _api_closewin + +[SECTION .text] + +_api_closewin: ; void api_closewin(int win); + PUSH EBX + MOV EDX,14 + MOV EBX,[ESP+8] ; win + INT 0x40 + POP EBX + RET diff --git a/30_day/apilib/api015.nas b/30_day/apilib/api015.nas new file mode 100644 index 0000000..bd27ec7 --- /dev/null +++ b/30_day/apilib/api015.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api015.nas"] + + GLOBAL _api_getkey + +[SECTION .text] + +_api_getkey: ; int api_getkey(int mode); + MOV EDX,15 + MOV EAX,[ESP+4] ; mode + INT 0x40 + RET diff --git a/30_day/apilib/api016.nas b/30_day/apilib/api016.nas new file mode 100644 index 0000000..e232412 --- /dev/null +++ b/30_day/apilib/api016.nas @@ -0,0 +1,13 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api016.nas"] + + GLOBAL _api_alloctimer + +[SECTION .text] + +_api_alloctimer: ; int api_alloctimer(void); + MOV EDX,16 + INT 0x40 + RET diff --git a/30_day/apilib/api017.nas b/30_day/apilib/api017.nas new file mode 100644 index 0000000..9e6a3cd --- /dev/null +++ b/30_day/apilib/api017.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api017.nas"] + + GLOBAL _api_inittimer + +[SECTION .text] + +_api_inittimer: ; void api_inittimer(int timer, int data); + PUSH EBX + MOV EDX,17 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; data + INT 0x40 + POP EBX + RET diff --git a/30_day/apilib/api018.nas b/30_day/apilib/api018.nas new file mode 100644 index 0000000..a91d6f1 --- /dev/null +++ b/30_day/apilib/api018.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api018.nas"] + + GLOBAL _api_settimer + +[SECTION .text] + +_api_settimer: ; void api_settimer(int timer, int time); + PUSH EBX + MOV EDX,18 + MOV EBX,[ESP+ 8] ; timer + MOV EAX,[ESP+12] ; time + INT 0x40 + POP EBX + RET diff --git a/30_day/apilib/api019.nas b/30_day/apilib/api019.nas new file mode 100644 index 0000000..d1c11e2 --- /dev/null +++ b/30_day/apilib/api019.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api019.nas"] + + GLOBAL _api_freetimer + +[SECTION .text] + +_api_freetimer: ; void api_freetimer(int timer); + PUSH EBX + MOV EDX,19 + MOV EBX,[ESP+ 8] ; timer + INT 0x40 + POP EBX + RET diff --git a/30_day/apilib/api020.nas b/30_day/apilib/api020.nas new file mode 100644 index 0000000..166bcda --- /dev/null +++ b/30_day/apilib/api020.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api020.nas"] + + GLOBAL _api_beep + +[SECTION .text] + +_api_beep: ; void api_beep(int tone); + MOV EDX,20 + MOV EAX,[ESP+4] ; tone + INT 0x40 + RET diff --git a/30_day/apilib/api021.nas b/30_day/apilib/api021.nas new file mode 100644 index 0000000..565a037 --- /dev/null +++ b/30_day/apilib/api021.nas @@ -0,0 +1,16 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api021.nas"] + + GLOBAL _api_fopen + +[SECTION .text] + +_api_fopen: ; int api_fopen(char *fname); + PUSH EBX + MOV EDX,21 + MOV EBX,[ESP+8] ; fname + INT 0x40 + POP EBX + RET diff --git a/30_day/apilib/api022.nas b/30_day/apilib/api022.nas new file mode 100644 index 0000000..a21f508 --- /dev/null +++ b/30_day/apilib/api022.nas @@ -0,0 +1,14 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api022.nas"] + + GLOBAL _api_fclose + +[SECTION .text] + +_api_fclose: ; void api_fclose(int fhandle); + MOV EDX,22 + MOV EAX,[ESP+4] ; fhandle + INT 0x40 + RET diff --git a/30_day/apilib/api023.nas b/30_day/apilib/api023.nas new file mode 100644 index 0000000..f34c33b --- /dev/null +++ b/30_day/apilib/api023.nas @@ -0,0 +1,18 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api023.nas"] + + GLOBAL _api_fseek + +[SECTION .text] + +_api_fseek: ; void api_fseek(int fhandle, int offset, int mode); + PUSH EBX + MOV EDX,23 + MOV EAX,[ESP+8] ; fhandle + MOV ECX,[ESP+16] ; mode + MOV EBX,[ESP+12] ; offset + INT 0x40 + POP EBX + RET diff --git a/30_day/apilib/api024.nas b/30_day/apilib/api024.nas new file mode 100644 index 0000000..5352889 --- /dev/null +++ b/30_day/apilib/api024.nas @@ -0,0 +1,15 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api024.nas"] + + GLOBAL _api_fsize + +[SECTION .text] + +_api_fsize: ; int api_fsize(int fhandle, int mode); + MOV EDX,24 + MOV EAX,[ESP+4] ; fhandle + MOV ECX,[ESP+8] ; mode + INT 0x40 + RET diff --git a/30_day/apilib/api025.nas b/30_day/apilib/api025.nas new file mode 100644 index 0000000..9f394d3 --- /dev/null +++ b/30_day/apilib/api025.nas @@ -0,0 +1,18 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api025.nas"] + + GLOBAL _api_fread + +[SECTION .text] + +_api_fread: ; int api_fread(char *buf, int maxsize, int fhandle); + PUSH EBX + MOV EDX,25 + MOV EAX,[ESP+16] ; fhandle + MOV ECX,[ESP+12] ; maxsize + MOV EBX,[ESP+8] ; buf + INT 0x40 + POP EBX + RET diff --git a/30_day/apilib/api026.nas b/30_day/apilib/api026.nas new file mode 100644 index 0000000..33bb2f5 --- /dev/null +++ b/30_day/apilib/api026.nas @@ -0,0 +1,17 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api026.nas"] + + GLOBAL _api_cmdline + +[SECTION .text] + +_api_cmdline: ; int api_cmdline(char *buf, int maxsize); + PUSH EBX + MOV EDX,26 + MOV ECX,[ESP+12] ; maxsize + MOV EBX,[ESP+8] ; buf + INT 0x40 + POP EBX + RET diff --git a/30_day/apilib/api027.nas b/30_day/apilib/api027.nas new file mode 100644 index 0000000..38bfbc1 --- /dev/null +++ b/30_day/apilib/api027.nas @@ -0,0 +1,13 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "api027.nas"] + + GLOBAL _api_getlang + +[SECTION .text] + +_api_getlang: ; int api_getlang(void); + MOV EDX,27 + INT 0x40 + RET diff --git a/30_day/apilib/apilib.lib b/30_day/apilib/apilib.lib new file mode 100644 index 0000000000000000000000000000000000000000..29a8eeebd154eb753bb6d0e59a2125dff5d57df1 GIT binary patch literal 8966 zcmeI2&uv5w%5XY3zgzHW)jywS}zIi{^ zs~^`oyY){J*V10ed5ca-)fYK*TCxI?b?20d;e=|w_fW&6}na@=PnqsV7Bha zllH#Z`liuxcX5h4?T34frc-RR8rFkav)SI2z1`<~9n-YOXg6AxJnfiN-K{$VG#f3` zDeN}e-9hQDY27!!m6wTISd9m!{SkCHS})$E;`RZ|rK z#|@ljv<` zk{TKXJq@0(S4Kv|fTU3jLBsIt#Z#JokY1dkHm1RSlte+J&l|wuM!?oo)Fa?YdgWaq z5Jr@J91^)TiH%C^Mx_v|Uh=Q{?=)o4s((anyz1OXNffL8`Da^wa!*(bQavlP)H}#5 z_bQnc(ug!^#8=xvJ5)&zgy-*-cLjt;4X_o;1C=^a4ne2vx7mNteS+v*rZ%R-eUwB) z=hLk|d5(-{iSR5Fo)yBACOny5Gjo{`-413{)-&R#@Je)y7U@RHA0;cozPqG!{eMD< zcOXHjLX}Af!2ca!tG6Ds^wv0udn73()F@y8O#*o;b z_d>5k$H8&G?9V=eLYT<^1PVXU?+X7jr?#AXi()kkTw9nBbg=@*)j4->8D{hBcrR-3nB Wt<|Qd)cUcbwAxHvcu(R_7XJe03V>?> literal 0 HcmV?d00001 diff --git a/30_day/apilib/make.bat b/30_day/apilib/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/apilib/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/app_make.txt b/30_day/app_make.txt new file mode 100644 index 0000000..b1e4436 --- /dev/null +++ b/30_day/app_make.txt @@ -0,0 +1,92 @@ +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ +APILIBPATH = ../apilib/ +STDLIBPATH = ../stdlib/ +HARIBOTEPATH = ../haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -I../ -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +BIM2BIN = $(TOOLPATH)bim2bin.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) $(APP).hrb + +#文件生成规则 + +$(APP).bim : $(APP).obj $(APILIBPATH)apilib.lib $(STDLIBPATH)stdlib.lib Makefile ../app_make.txt + $(OBJ2BIM) @$(RULEFILE) out:$(APP).bim map:$(APP).map stack:$(STACK) \ + $(APP).obj $(APILIBPATH)apilib.lib $(STDLIBPATH)stdlib.lib + +$(STDAPP).bim : $(APP).obj $(STDLIBPATH)stdlib.lib Makefile ../app_make.txt + $(OBJ2BIM) @$(RULEFILE) out:$(APP).bim map:$(APP).map stack:$(STACK) \ + $(APP).obj $(STDLIBPATH)stdlib.lib + +haribote.img : ../haribote/ipl20.bin ../haribote/haribote.sys $(APP).hrb \ + Makefile ../app_make.txt + $(EDIMG) imgin:../../z_tools/fdimg0at.tek \ + wbinimg src:../haribote/ipl20.bin len:512 from:0 to:0 \ + copy from:../haribote/haribote.sys to:@: \ + copy from:$(APP).hrb to:@: \ + copy from:../nihongo/nihongo.fnt to:@: \ + imgout:haribote.img + +#一般规则 + +%.gas : %.c ../apilib.h ../stdlib.h Makefile ../app_make.txt + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile ../app_make.txt + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile ../app_make.txt + $(NASK) $*.nas $*.obj $*.lst + +%.org : %.bim Makefile ../app_make.txt + $(BIM2HRB) $*.bim $*.org $(MALLOC) + +%.hrb : %.org Makefile ../app_make.txt + $(BIM2BIN) -osacmp in:$*.org out:$*.hrb + +#命令 + +run : + $(MAKE) haribote.img + $(COPY) haribote.img ..\..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../../z_tools/qemu + +full : + $(MAKE) -C $(APILIBPATH) + $(MAKE) -C $(STDLIBPATH) + $(MAKE) $(APP).hrb + +run_full : + $(MAKE) -C $(APILIBPATH) + $(MAKE) -C $(STDLIBPATH) + $(MAKE) -C ../haribote + $(MAKE) run + +clean : + -$(DEL) *.lst + -$(DEL) *.obj + -$(DEL) *.map + -$(DEL) *.bim + -$(DEL) *.org + -$(DEL) haribote.img + +src_only : + $(MAKE) clean + -$(DEL) $(APP).hrb diff --git a/30_day/bball/!cons_9x.bat b/30_day/bball/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/bball/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/bball/!cons_nt.bat b/30_day/bball/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/bball/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/bball/Makefile b/30_day/bball/Makefile new file mode 100644 index 0000000..b976252 --- /dev/null +++ b/30_day/bball/Makefile @@ -0,0 +1,5 @@ +APP = bball +STACK = 52k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/bball/bball.c b/30_day/bball/bball.c new file mode 100644 index 0000000..23a5d67 --- /dev/null +++ b/30_day/bball/bball.c @@ -0,0 +1,37 @@ +#include "apilib.h" + +void HariMain(void) +{ + int win, i, j, dis; + char buf[216 * 237]; + struct POINT { + int x, y; + }; + static struct POINT table[16] = { + { 204, 129 }, { 195, 90 }, { 172, 58 }, { 137, 38 }, { 98, 34 }, + { 61, 46 }, { 31, 73 }, { 15, 110 }, { 15, 148 }, { 31, 185 }, + { 61, 212 }, { 98, 224 }, { 137, 220 }, { 172, 200 }, { 195, 168 }, + { 204, 129 } + }; + + win = api_openwin(buf, 216, 237, -1, "bball"); + api_boxfilwin(win, 8, 29, 207, 228, 0); + for (i = 0; i <= 14; i++) { + for (j = i + 1; j <= 15; j++) { + dis = j - i; /*两点间的距离*/ + if (dis >= 8) { + dis = 15 - dis; /*逆向计数*/ + } + if (dis != 0) { + api_linewin(win, table[i].x, table[i].y, table[j].x, table[j].y, 8 - dis); + } + } + } + + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/30_day/bball/make.bat b/30_day/bball/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/bball/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/beepdown/!cons_9x.bat b/30_day/beepdown/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/beepdown/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/beepdown/!cons_nt.bat b/30_day/beepdown/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/beepdown/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/beepdown/Makefile b/30_day/beepdown/Makefile new file mode 100644 index 0000000..ffd14fa --- /dev/null +++ b/30_day/beepdown/Makefile @@ -0,0 +1,5 @@ +APP = beepdown +STACK = 1k +MALLOC = 40k + +include ../app_make.txt diff --git a/30_day/beepdown/beepdown.c b/30_day/beepdown/beepdown.c new file mode 100644 index 0000000..d08962c --- /dev/null +++ b/30_day/beepdown/beepdown.c @@ -0,0 +1,19 @@ +#include "apilib.h" + +void HariMain(void) +{ + int i, timer; + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (i = 20000000; i >= 20000; i -= i / 100) { + /* 20KHz~20Hz,即人类可以听到的声音范围*/ + /* i以1%的速度递减*/ + api_beep(i); + api_settimer(timer, 1); /* 0.01秒*/ + if (api_getkey(1) != 128) { + break; + } + } + api_beep(0); + api_end(); +} diff --git a/30_day/beepdown/make.bat b/30_day/beepdown/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/beepdown/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/chklang/!cons_9x.bat b/30_day/chklang/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/chklang/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/chklang/!cons_nt.bat b/30_day/chklang/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/chklang/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/chklang/Makefile b/30_day/chklang/Makefile new file mode 100644 index 0000000..c00ebbc --- /dev/null +++ b/30_day/chklang/Makefile @@ -0,0 +1,5 @@ +APP = chklang +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/chklang/chklang.c b/30_day/chklang/chklang.c new file mode 100644 index 0000000..3c28491 --- /dev/null +++ b/30_day/chklang/chklang.c @@ -0,0 +1,24 @@ +#include "apilib.h" + +void HariMain(void) +{ + int langmode = api_getlang(); + static char s1[23] = { /* 日本語シフトJISモード(日文Shift-JIS模式)*/ + 0x93, 0xfa, 0x96, 0x7b, 0x8c, 0xea, 0x83, 0x56, 0x83, 0x74, 0x83, 0x67, + 0x4a, 0x49, 0x53, 0x83, 0x82, 0x81, 0x5b, 0x83, 0x68, 0x0a, 0x00 + }; + static char s2[17] = { /*日本語EUCモード(日文EUC模式)*/ + 0xc6, 0xfc, 0xcb, 0xdc, 0xb8, 0xec, 0x45, 0x55, 0x43, 0xa5, 0xe2, 0xa1, + 0xbc, 0xa5, 0xc9, 0x0a, 0x00 + }; + if (langmode == 0) { + api_putstr0("English ASCII mode\n"); + } + if (langmode == 1) { + api_putstr0(s1); + } + if (langmode == 2) { + api_putstr0(s2); + } + api_end(); +} diff --git a/30_day/chklang/make.bat b/30_day/chklang/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/chklang/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/color/!cons_9x.bat b/30_day/color/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/color/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/color/!cons_nt.bat b/30_day/color/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/color/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/color/Makefile b/30_day/color/Makefile new file mode 100644 index 0000000..614dac9 --- /dev/null +++ b/30_day/color/Makefile @@ -0,0 +1,5 @@ +APP = color +STACK = 1k +MALLOC = 56k + +include ../app_make.txt diff --git a/30_day/color/color.c b/30_day/color/color.c new file mode 100644 index 0000000..ce228e2 --- /dev/null +++ b/30_day/color/color.c @@ -0,0 +1,21 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win, x, y, r, g, b; + api_initmalloc(); + buf = api_malloc(144 * 164); + win = api_openwin(buf, 144, 164, -1, "color"); + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) { + r = x * 2; + g = y * 2; + b = 0; + buf[(x + 8) + (y + 28) * 144] = 16 + (r / 43) + (g / 43) * 6 + (b / 43) * 36; + } + } + api_refreshwin(win, 8, 28, 136, 156); + api_getkey(1); /*等待按下任意键*/ + api_end(); +} diff --git a/30_day/color/make.bat b/30_day/color/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/color/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/color2/!cons_9x.bat b/30_day/color2/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/color2/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/color2/!cons_nt.bat b/30_day/color2/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/color2/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/color2/Makefile b/30_day/color2/Makefile new file mode 100644 index 0000000..93b5f23 --- /dev/null +++ b/30_day/color2/Makefile @@ -0,0 +1,5 @@ +APP = color2 +STACK = 1k +MALLOC = 56k + +include ../app_make.txt diff --git a/30_day/color2/color2.c b/30_day/color2/color2.c new file mode 100644 index 0000000..82e3f6a --- /dev/null +++ b/30_day/color2/color2.c @@ -0,0 +1,36 @@ +#include "apilib.h" + +unsigned char rgb2pal(int r, int g, int b, int x, int y); + +void HariMain(void) +{ + char *buf; + int win, x, y; + api_initmalloc(); + buf = api_malloc(144 * 164); + win = api_openwin(buf, 144, 164, -1, "color2"); + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) { + buf[(x + 8) + (y + 28) * 144] = rgb2pal(x * 2, y * 2, 0, x, y); + } + } + api_refreshwin(win, 8, 28, 136, 156); + api_getkey(1); /* �Ă��Ƃ��ȃL�[���͂�҂� */ + api_end(); +} + +unsigned char rgb2pal(int r, int g, int b, int x, int y) +{ + static int table[4] = { 3, 1, 0, 2 }; + int i; + x &= 1; /*判断是偶数还是奇数*/ + y &= 1; + i = table[x + y * 2]; /*用来生成中间色的常量*/ + r = (r * 21) / 256; /* r为0~20*/ + g = (g * 21) / 256; + b = (b * 21) / 256; + r = (r + i) / 4; /* r为0~5*/ + g = (g + i) / 4; + b = (b + i) / 4; + return 16 + r + g * 6 + b * 36; +} diff --git a/30_day/color2/make.bat b/30_day/color2/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/color2/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/euc.txt b/30_day/euc.txt new file mode 100644 index 0000000..ae6d81a --- /dev/null +++ b/30_day/euc.txt @@ -0,0 +1 @@ +ܸEUCǽ񤤤Ƥߤ衼 diff --git a/30_day/haribote.rul b/30_day/haribote.rul new file mode 100644 index 0000000..ee8f67b --- /dev/null +++ b/30_day/haribote.rul @@ -0,0 +1,10 @@ +format: + code(align:1, logic:0x24, file:0x24); + data(align:4, logic:stack_end, file:code_end); + +file: + ../../z_tools/haribote/harilibc.lib; + ../../z_tools/haribote/golibc.lib; + +label: + _HariStartup; diff --git a/30_day/haribote/!cons_9x.bat b/30_day/haribote/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/haribote/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/haribote/!cons_nt.bat b/30_day/haribote/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/haribote/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/haribote/Makefile b/30_day/haribote/Makefile new file mode 100644 index 0000000..6844a71 --- /dev/null +++ b/30_day/haribote/Makefile @@ -0,0 +1,79 @@ +OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \ + int.obj fifo.obj keyboard.obj mouse.obj memory.obj sheet.obj timer.obj \ + mtask.obj window.obj console.obj file.obj tek.obj + +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) ipl20.bin + $(MAKE) haribote.sys + +# 镜像文件生成 + +ipl20.bin : ipl20.nas Makefile + $(NASK) ipl20.nas ipl20.bin ipl20.lst + +asmhead.bin : asmhead.nas Makefile + $(NASK) asmhead.nas asmhead.bin asmhead.lst + +hankaku.bin : hankaku.txt Makefile + $(MAKEFONT) hankaku.txt hankaku.bin + +hankaku.obj : hankaku.bin Makefile + $(BIN2OBJ) hankaku.bin hankaku.obj _hankaku + +bootpack.bim : $(OBJS_BOOTPACK) Makefile + $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \ + $(OBJS_BOOTPACK) +# 3MB+64KB=3136KB + +bootpack.hrb : bootpack.bim Makefile + $(BIM2HRB) bootpack.bim bootpack.hrb 0 + +haribote.sys : asmhead.bin bootpack.hrb Makefile + copy /B asmhead.bin+bootpack.hrb haribote.sys + +# 其他指令 + +%.gas : %.c bootpack.h Makefile + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +# 运行程序 + +clean : + -$(DEL) asmhead.bin + -$(DEL) hankaku.bin + -$(DEL) *.lst + -$(DEL) *.obj + -$(DEL) *.map + -$(DEL) *.bim + -$(DEL) *.hrb + +src_only : + $(MAKE) clean + -$(DEL) ipl20.bin + -$(DEL) haribote.sys diff --git a/30_day/haribote/asmhead.nas b/30_day/haribote/asmhead.nas new file mode 100644 index 0000000..ad35d76 --- /dev/null +++ b/30_day/haribote/asmhead.nas @@ -0,0 +1,202 @@ +; haribote-os boot asm +; TAB=4 + +[INSTRSET "i486p"] + +VBEMODE EQU 0x105 ; 1024 x 768 x 8bit 彩色 +; 显示模式 +; 0x100 : 640 x 400 x 8bit 彩色 +; 0x101 : 640 x 480 x 8bit 彩色 +; 0x103 : 800 x 600 x 8bit 彩色 +; 0x105 : 1024 x 768 x 8bit 彩色 +; 0x107 : 1280 x 1024 x 8bit 彩色 + +BOTPAK EQU 0x00280000 ; 加载bootpack +DSKCAC EQU 0x00100000 ; 磁盘缓存的位置 +DSKCAC0 EQU 0x00008000 ; 磁盘缓存的位置(实模式) + +; BOOT_INFO 相关 +CYLS EQU 0x0ff0 ; 引导扇区设置 +LEDS EQU 0x0ff1 +VMODE EQU 0x0ff2 ; 关于颜色的信息 +SCRNX EQU 0x0ff4 ; 分辨率X +SCRNY EQU 0x0ff6 ; 分辨率Y +VRAM EQU 0x0ff8 ; 图像缓冲区的起始地址 + + ORG 0xc200 ; 这个的程序要被装载的内存地址 + +; 确认VBE是否存在 + + MOV AX,0x9000 + MOV ES,AX + MOV DI,0 + MOV AX,0x4f00 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 检查VBE的版本 + + MOV AX,[ES:DI+4] + CMP AX,0x0200 + JB scrn320 ; if (AX < 0x0200) goto scrn320 + +; 取得画面模式信息 + + MOV CX,VBEMODE + MOV AX,0x4f01 + INT 0x10 + CMP AX,0x004f + JNE scrn320 + +; 画面模式信息的确认 + CMP BYTE [ES:DI+0x19],8 ;颜色数必须为8 + JNE scrn320 + CMP BYTE [ES:DI+0x1b],4 ;颜色的指定方法必须为4(4是调色板模式) + JNE scrn320 + MOV AX,[ES:DI+0x00] ;模式属性bit7不是1就不能加上0x4000 + AND AX,0x0080 + JZ scrn320 ; 模式属性的bit7是0,所以放弃 + +; 画面设置 + + MOV BX,VBEMODE+0x4000 + MOV AX,0x4f02 + INT 0x10 + MOV BYTE [VMODE],8 ; 屏幕的模式(参考C语言的引用) + MOV AX,[ES:DI+0x12] + MOV [SCRNX],AX + MOV AX,[ES:DI+0x14] + MOV [SCRNY],AX + MOV EAX,[ES:DI+0x28] ;VRAM的地址 + MOV [VRAM],EAX + JMP keystatus + +scrn320: + MOV AL,0x13 ; VGA图、320x200x8bit彩色 + MOV AH,0x00 + INT 0x10 + MOV BYTE [VMODE],8 ; 记下画面模式(参考C语言) + MOV WORD [SCRNX],320 + MOV WORD [SCRNY],200 + MOV DWORD [VRAM],0x000a0000 + +; 通过 BIOS 获取指示灯状态 + +keystatus: + MOV AH,0x02 + INT 0x16 ; keyboard BIOS + MOV [LEDS],AL + +; PIC关闭一切中断 +; 根据AT兼容机的规格,如果要初始化PIC, +; 必须在CLI之前进行,否则有时会挂起。 +; 随后进行PIC的初始化。 + + MOV AL,0xff + OUT 0x21,AL + NOP ; 如果连续执行OUT指令,有些机种会无法正常运行 + OUT 0xa1,AL + + CLI ; 禁止CPU级别的中断 + +; 为了让CPU能够访问1MB以上的内存空间,设定A20GATE + + CALL waitkbdout + MOV AL,0xd1 + OUT 0x64,AL + CALL waitkbdout + MOV AL,0xdf ; enable A20 + OUT 0x60,AL + CALL waitkbdout + +; 切换到保护模式 + +[INSTRSET "i486p"] ; 说明使用486指令 + + LGDT [GDTR0] ; 设置临时GDT + MOV EAX,CR0 + AND EAX,0x7fffffff ; 设bit31为0(禁用分页) + OR EAX,0x00000001 ; bit0到1转换(保护模式过渡) + MOV CR0,EAX + JMP pipelineflush +pipelineflush: + MOV AX,1*8 ; 可读写的段 32bit + MOV DS,AX + MOV ES,AX + MOV FS,AX + MOV GS,AX + MOV SS,AX + +; bootpack传递 + + MOV ESI,bootpack ; 转送源 + MOV EDI,BOTPAK ; 转送目标 + MOV ECX,512*1024/4 + CALL memcpy + +; 磁盘数据最终转送到它本来的位置去 +; 首先从启动扇区开始 + + MOV ESI,0x7c00 ; 转送源 + MOV EDI,DSKCAC ; 转送目标 + MOV ECX,512/4 + CALL memcpy + +; 剩余的全部 + + MOV ESI,DSKCAC0+512 ; 转送源 + MOV EDI,DSKCAC+512 ; 转送源目标 + MOV ECX,0 + MOV CL,BYTE [CYLS] + IMUL ECX,512*18*2/4 ; 从柱面数变换为字节数/4 + SUB ECX,512/4 ; 减去 IPL 偏移量 + CALL memcpy + +; 必须由asmhead来完成的工作,至此全部完毕 +; 以后就交由bootpack来完成 + +; bootpack启动 + + MOV EBX,BOTPAK + MOV ECX,[EBX+16] + ADD ECX,3 ; ECX += 3; + SHR ECX,2 ; ECX /= 4; + JZ skip ; 没有要转送的东西时 + MOV ESI,[EBX+20] ; 转送源 + ADD ESI,EBX + MOV EDI,[EBX+12] ; 转送目标 + CALL memcpy +skip: + MOV ESP,[EBX+12] ; 堆栈的初始化 + JMP DWORD 2*8:0x0000001b + +waitkbdout: + IN AL,0x64 + AND AL,0x02 + JNZ waitkbdout ; AND的结果如果不是0,就跳到waitkbdout + RET + +memcpy: + MOV EAX,[ESI] + ADD ESI,4 + MOV [EDI],EAX + ADD EDI,4 + SUB ECX,1 + JNZ memcpy ; 减法运算的结果如果不是0,就跳转到memcpy + RET +; memcpy地址前缀大小 + + ALIGNB 16 +GDT0: + RESB 8 ; 初始值 + DW 0xffff,0x0000,0x9200,0x00cf ; 可以读写的段(segment)32bit + DW 0xffff,0x0000,0x9a28,0x0047 ; 可执行的文件的32bit寄存器(bootpack用) + + DW 0 +GDTR0: + DW 8*3-1 + DD GDT0 + + ALIGNB 16 +bootpack: diff --git a/30_day/haribote/bootpack.c b/30_day/haribote/bootpack.c new file mode 100644 index 0000000..4a0000b --- /dev/null +++ b/30_day/haribote/bootpack.c @@ -0,0 +1,412 @@ +/* bootpack */ + +#include "bootpack.h" +#include + +#define KEYCMD_LED 0xed + +void keywin_off(struct SHEET *key_win); +void keywin_on(struct SHEET *key_win); +void close_console(struct SHEET *sht); +void close_constask(struct TASK *task); + +void HariMain(void) +{ + struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; + struct SHTCTL *shtctl; + char s[40]; + struct FIFO32 fifo, keycmd; + int fifobuf[128], keycmd_buf[32]; + int mx, my, i, new_mx = -1, new_my = 0, new_wx = 0x7fffffff, new_wy = 0; + unsigned int memtotal; + struct MOUSE_DEC mdec; + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + unsigned char *buf_back, buf_mouse[256]; + struct SHEET *sht_back, *sht_mouse; + struct TASK *task_a, *task; + static char keytable0[0x80] = { + 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0x08, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0x0a, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0x5c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0 + }; + static char keytable1[0x80] = { + 0, 0, '!', 0x22, '#', '$', '%', '&', 0x27, '(', ')', '~', '=', '~', 0x08, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0x0a, 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', '+', '*', 0, 0, '}', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, '|', 0, 0 + }; + int key_shift = 0, key_leds = (binfo->leds >> 4) & 7, keycmd_wait = -1; + int j, x, y, mmx = -1, mmy = -1, mmx2 = 0; + struct SHEET *sht = 0, *key_win, *sht2; + int *fat; + unsigned char *nihongo; + struct FILEINFO *finfo; + extern char hankaku[4096]; + + init_gdtidt(); + init_pic(); + io_sti(); /* IDT/PIC的初始化已经完成,于是开放CPU的中断 */ + fifo32_init(&fifo, 128, fifobuf, 0); + *((int *) 0x0fec) = (int) &fifo; + init_pit(); + init_keyboard(&fifo, 256); + enable_mouse(&fifo, 512, &mdec); + io_out8(PIC0_IMR, 0xf8); /* 设定PIT和PIC1以及键盘为许可(11111000) */ + io_out8(PIC1_IMR, 0xef); /* 开放鼠标中断(11101111) */ + fifo32_init(&keycmd, 32, keycmd_buf, 0); + + memtotal = memtest(0x00400000, 0xbfffffff); + memman_init(memman); + memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */ + memman_free(memman, 0x00400000, memtotal - 0x00400000); + + init_palette(); + shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny); + task_a = task_init(memman); + fifo.task = task_a; + task_run(task_a, 1, 2); + *((int *) 0x0fe4) = (int) shtctl; + task_a->langmode = 0; + + /* sht_back */ + sht_back = sheet_alloc(shtctl); + buf_back = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny); + sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 无透明色 */ + init_screen8(buf_back, binfo->scrnx, binfo->scrny); + + /* sht_cons */ + key_win = open_console(shtctl, memtotal); + + /* sht_mouse */ + sht_mouse = sheet_alloc(shtctl); + sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99); + init_mouse_cursor8(buf_mouse, 99); + mx = (binfo->scrnx - 16) / 2; /* 计算坐标使其位于画面中央 */ + my = (binfo->scrny - 28 - 16) / 2; + + sheet_slide(sht_back, 0, 0); + sheet_slide(key_win, 32, 4); + sheet_slide(sht_mouse, mx, my); + sheet_updown(sht_back, 0); + sheet_updown(key_win, 1); + sheet_updown(sht_mouse, 2); + keywin_on(key_win); + + /* 为了避免和键盘当前状态冲突,在一开始先进行设置 */ + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + + /* 载入nihongo.fnt */ + fat = (int *) memman_alloc_4k(memman, 4 * 2880); + file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); + + finfo = file_search("nihongo.fnt", (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + if (finfo != 0) { + i = finfo->size; + nihongo = file_loadfile2(finfo->clustno, &i, fat); + } else { + nihongo = (unsigned char *) memman_alloc_4k(memman, 16 * 256 + 32 * 94 * 47); + for (i = 0; i < 16 * 256; i++) { + nihongo[i] = hankaku[i]; /*没有字库,半角部分直接复制英文字库*/ + } + for (i = 16 * 256; i < 16 * 256 + 32 * 94 * 47; i++) { + nihongo[i] = 0xff; /* 没有字库,全角部分以0xff填充 */ + } + } + *((int *) 0x0fe8) = (int) nihongo; + memman_free_4k(memman, (int) fat, 4 * 2880); + + for (;;) { + if (fifo32_status(&keycmd) > 0 && keycmd_wait < 0) { + /* 如果存在向键盘控制器发送的数据,则发送它 */ + keycmd_wait = fifo32_get(&keycmd); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + io_cli(); + if (fifo32_status(&fifo) == 0) { + /* FIFO为空,当存在搁置的绘图操作时立即执行*/ + if (new_mx >= 0) { + io_sti(); + sheet_slide(sht_mouse, new_mx, new_my); + new_mx = -1; + } else if (new_wx != 0x7fffffff) { + io_sti(); + sheet_slide(sht, new_wx, new_wy); + new_wx = 0x7fffffff; + } else { + task_sleep(task_a); + io_sti(); + } + } else { + i = fifo32_get(&fifo); + io_sti(); + if (key_win != 0 && key_win->flags == 0) { /*窗口被关闭*/ + if (shtctl->top == 1) { /*当画面上只剩鼠标和背景时*/ + key_win = 0; + } else { + key_win = shtctl->sheets[shtctl->top - 1]; + keywin_on(key_win); + } + } + if (256 <= i && i <= 511) { /* 键盘数据*/ + if (i < 0x80 + 256) { /*将按键编码转换为字符编码*/ + if (key_shift == 0) { + s[0] = keytable0[i - 256]; + } else { + s[0] = keytable1[i - 256]; + } + } else { + s[0] = 0; + } + if ('A' <= s[0] && s[0] <= 'Z') { /*当输入字符为英文字母时*/ + if (((key_leds & 4) == 0 && key_shift == 0) || + ((key_leds & 4) != 0 && key_shift != 0)) { + s[0] += 0x20; /*将大写字母转换为小写字母*/ + } + } + if (s[0] != 0 && key_win != 0) { /*一般字符、退格键、回车键*/ + fifo32_put(&key_win->task->fifo, s[0] + 256); + } + if (i == 256 + 0x0f && key_win != 0) { /* Tab键 */ + keywin_off(key_win); + j = key_win->height - 1; + if (j == 0) { + j = shtctl->top - 1; + } + key_win = shtctl->sheets[j]; + keywin_on(key_win); + } + if (i == 256 + 0x2a) { /*左Shift ON */ + key_shift |= 1; + } + if (i == 256 + 0x36) { /*右Shift ON */ + key_shift |= 2; + } + if (i == 256 + 0xaa) { /*左Shift OFF */ + key_shift &= ~1; + } + if (i == 256 + 0xb6) { /*右Shift OFF */ + key_shift &= ~2; + } + if (i == 256 + 0x3a) { /* CapsLock */ + key_leds ^= 4; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x45) { /* NumLock */ + key_leds ^= 2; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x46) { /* ScrollLock */ + key_leds ^= 1; + fifo32_put(&keycmd, KEYCMD_LED); + fifo32_put(&keycmd, key_leds); + } + if (i == 256 + 0x3b && key_shift != 0 && key_win != 0) { /* Shift+F1 */ + task = key_win->task; + if (task != 0 && task->tss.ss0 != 0) { + cons_putstr0(task->cons, "\nBreak(key) :\n"); + io_cli(); /*强制结束处理时禁止任务切换*/ + task->tss.eax = (int) &(task->tss.esp0); + task->tss.eip = (int) asm_end_app; + io_sti(); + task_run(task, -1, 0); /*为了确实执行结束处理,如果处于休眠状态则唤醒*/ + } + } + if (i == 256 + 0x3c && key_shift != 0) { /* Shift+F2 */ + if (key_win != 0) { + keywin_off(key_win); + } + key_win = open_console(shtctl, memtotal); + sheet_slide(key_win, 32, 4); + sheet_updown(key_win, shtctl->top); + keywin_on(key_win); + } + if (i == 256 + 0x57) { /* F11 */ + sheet_updown(shtctl->sheets[1], shtctl->top - 1); + } + if (i == 256 + 0xfa) { /*键盘成功接收到数据*/ + keycmd_wait = -1; + } + if (i == 256 + 0xfe) { /*键盘没有成功接收到数据*/ + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, keycmd_wait); + } + } else if (512 <= i && i <= 767) { /* 鼠标数据*/ + if (mouse_decode(&mdec, i - 512) != 0) { + /* 已经收集了3字节的数据,移动光标 */ + mx += mdec.x; + my += mdec.y; + if (mx < 0) { + mx = 0; + } + if (my < 0) { + my = 0; + } + if (mx > binfo->scrnx - 1) { + mx = binfo->scrnx - 1; + } + if (my > binfo->scrny - 1) { + my = binfo->scrny - 1; + } + new_mx = mx; + new_my = my; + if ((mdec.btn & 0x01) != 0) { /* 按下左键 */ + if (mmx < 0) { + /*如果处于通常模式*/ + /*按照从上到下的顺序寻找鼠标所指向的图层*/ + for (j = shtctl->top - 1; j > 0; j--) { + sht = shtctl->sheets[j]; + x = mx - sht->vx0; + y = my - sht->vy0; + if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) { + if (sht->buf[y * sht->bxsize + x] != sht->col_inv) { + sheet_updown(sht, shtctl->top - 1); + if (sht != key_win) { + keywin_off(key_win); + key_win = sht; + keywin_on(key_win); + } + if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) { + mmx = mx; /*进入窗口移动模式*/ + mmy = my; + mmx2 = sht->vx0; + new_wy = sht->vy0; + } + if (sht->bxsize - 21 <= x && x < sht->bxsize - 5 && 5 <= y && y < 19) { + /*点击“×”按钮*/ + if ((sht->flags & 0x10) != 0) { /*该窗口是否为应用程序窗口?*/ + task = sht->task; + cons_putstr0(task->cons, "\nBreak(mouse) :\n"); + io_cli(); /*强制结束处理时禁止任务切换*/ + task->tss.eax = (int) &(task->tss.esp0); + task->tss.eip = (int) asm_end_app; + io_sti(); + task_run(task, -1, 0); + } else { /*命令行窗口*/ + task = sht->task; + sheet_updown(sht, -1); /*暂且隐藏该图层*/ + keywin_off(key_win); + key_win = shtctl->sheets[shtctl->top - 1]; + keywin_on(key_win); + io_cli(); + fifo32_put(&task->fifo, 4); + io_sti(); + } + } + break; + } + } + } + } else { + /*如果处于窗口移动模式*/ + x = mx - mmx; /*计算鼠标指针移动量*/ + y = my - mmy; + new_wx = (mmx2 + x + 2) & ~3; + new_wy = new_wy + y; + mmy = my; + } + } else { + /*没有按下左键*/ + mmx = -1; /*切换到一般模式*/ + if (new_wx != 0x7fffffff) { + sheet_slide(sht, new_wx, new_wy); /*固定图层位置*/ + new_wx = 0x7fffffff; + } + } + } + } else if (768 <= i && i <= 1023) { /*命令行窗口关闭处理*/ + close_console(shtctl->sheets0 + (i - 768)); + } else if (1024 <= i && i <= 2023) { + close_constask(taskctl->tasks0 + (i - 1024)); + } else if (2024 <= i && i <= 2279) { /*只关闭命令行窗口*/ + sht2 = shtctl->sheets0 + (i - 2024); + memman_free_4k(memman, (int) sht2->buf, 256 * 165); + sheet_free(sht2); + } + } + } +} + +void keywin_off(struct SHEET *key_win) +{ + change_wtitle8(key_win, 0); + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 3); /*命令行窗口光标OFF */ + } + return; +} + +void keywin_on(struct SHEET *key_win) +{ + change_wtitle8(key_win, 1); + if ((key_win->flags & 0x20) != 0) { + fifo32_put(&key_win->task->fifo, 2); /*命令行窗口光标ON */ + } + return; +} + +struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = task_alloc(); + int *cons_fifo = (int *) memman_alloc_4k(memman, 128 * 4); + task->cons_stack = memman_alloc_4k(memman, 64 * 1024); + task->tss.esp = task->cons_stack + 64 * 1024 - 12; + task->tss.eip = (int) &console_task; + task->tss.es = 1 * 8; + task->tss.cs = 2 * 8; + task->tss.ss = 1 * 8; + task->tss.ds = 1 * 8; + task->tss.fs = 1 * 8; + task->tss.gs = 1 * 8; + *((int *) (task->tss.esp + 4)) = (int) sht; + *((int *) (task->tss.esp + 8)) = memtotal; + task_run(task, 2, 2); /* level=2, priority=2 */ + fifo32_init(&task->fifo, 128, cons_fifo, task); + return task; +} + +struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct SHEET *sht = sheet_alloc(shtctl); + unsigned char *buf = (unsigned char *) memman_alloc_4k(memman, 256 * 165); + sheet_setbuf(sht, buf, 256, 165, -1); /*无透明色*/ + make_window8(buf, 256, 165, "console", 0); + make_textbox8(sht, 8, 28, 240, 128, COL8_000000); + sht->task = open_constask(sht, memtotal); + sht->flags |= 0x20; /*有光标*/ + return sht; +} + +void close_constask(struct TASK *task) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + task_sleep(task); + memman_free_4k(memman, task->cons_stack, 64 * 1024); + memman_free_4k(memman, (int) task->fifo.buf, 128 * 4); + task->flags = 0; /*用来替代task_free(task); */ + return; +} + +void close_console(struct SHEET *sht) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = sht->task; + memman_free_4k(memman, (int) sht->buf, 256 * 165); + sheet_free(sht); + close_constask(task); + return; +} diff --git a/30_day/haribote/bootpack.h b/30_day/haribote/bootpack.h new file mode 100644 index 0000000..bb195ff --- /dev/null +++ b/30_day/haribote/bootpack.h @@ -0,0 +1,297 @@ +/* asmhead.nas */ +struct BOOTINFO { /* 0x0ff0-0x0fff */ + char cyls; /* 启动区读磁盘读到此为止 */ + char leds; /* 启动时键盘的LED的状态 */ + char vmode; /* 显卡模式为多少位彩色 */ + char reserve; + short scrnx, scrny; /* 画面分辨率 */ + char *vram; +}; +#define ADR_BOOTINFO 0x00000ff0 +#define ADR_DISKIMG 0x00100000 + +/* naskfunc.nas */ +void io_hlt(void); +void io_cli(void); +void io_sti(void); +void io_stihlt(void); +int io_in8(int port); +void io_out8(int port, int data); +int io_load_eflags(void); +void io_store_eflags(int eflags); +void load_gdtr(int limit, int addr); +void load_idtr(int limit, int addr); +int load_cr0(void); +void store_cr0(int cr0); +void load_tr(int tr); +void asm_inthandler0c(void); +void asm_inthandler0d(void); +void asm_inthandler20(void); +void asm_inthandler21(void); +void asm_inthandler2c(void); +unsigned int memtest_sub(unsigned int start, unsigned int end); +void farjmp(int eip, int cs); +void farcall(int eip, int cs); +void asm_hrb_api(void); +void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); +void asm_end_app(void); + +/* fifo.c */ +struct FIFO32 { + int *buf; + int p, q, size, free, flags; + struct TASK *task; +}; +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task); +int fifo32_put(struct FIFO32 *fifo, int data); +int fifo32_get(struct FIFO32 *fifo); +int fifo32_status(struct FIFO32 *fifo); + +/* graphic.c */ +void init_palette(void); +void set_palette(int start, int end, unsigned char *rgb); +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); +void init_screen8(char *vram, int x, int y); +void putfont8(char *vram, int xsize, int x, int y, char c, char *font); +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s); +void init_mouse_cursor8(char *mouse, char bc); +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize); +#define COL8_000000 0 +#define COL8_FF0000 1 +#define COL8_00FF00 2 +#define COL8_FFFF00 3 +#define COL8_0000FF 4 +#define COL8_FF00FF 5 +#define COL8_00FFFF 6 +#define COL8_FFFFFF 7 +#define COL8_C6C6C6 8 +#define COL8_840000 9 +#define COL8_008400 10 +#define COL8_848400 11 +#define COL8_000084 12 +#define COL8_840084 13 +#define COL8_008484 14 +#define COL8_848484 15 + +/* dsctbl.c */ +struct SEGMENT_DESCRIPTOR { + short limit_low, base_low; + char base_mid, access_right; + char limit_high, base_high; +}; +struct GATE_DESCRIPTOR { + short offset_low, selector; + char dw_count, access_right; + short offset_high; +}; +void init_gdtidt(void); +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar); +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar); +#define ADR_IDT 0x0026f800 +#define LIMIT_IDT 0x000007ff +#define ADR_GDT 0x00270000 +#define LIMIT_GDT 0x0000ffff +#define ADR_BOTPAK 0x00280000 +#define LIMIT_BOTPAK 0x0007ffff +#define AR_DATA32_RW 0x4092 +#define AR_CODE32_ER 0x409a +#define AR_LDT 0x0082 +#define AR_TSS32 0x0089 +#define AR_INTGATE32 0x008e + +/* int.c */ +void init_pic(void); +#define PIC0_ICW1 0x0020 +#define PIC0_OCW2 0x0020 +#define PIC0_IMR 0x0021 +#define PIC0_ICW2 0x0021 +#define PIC0_ICW3 0x0021 +#define PIC0_ICW4 0x0021 +#define PIC1_ICW1 0x00a0 +#define PIC1_OCW2 0x00a0 +#define PIC1_IMR 0x00a1 +#define PIC1_ICW2 0x00a1 +#define PIC1_ICW3 0x00a1 +#define PIC1_ICW4 0x00a1 + +/* keyboard.c */ +void inthandler21(int *esp); +void wait_KBC_sendready(void); +void init_keyboard(struct FIFO32 *fifo, int data0); +#define PORT_KEYDAT 0x0060 +#define PORT_KEYCMD 0x0064 + +/* mouse.c */ +struct MOUSE_DEC { + unsigned char buf[3], phase; + int x, y, btn; +}; +void inthandler2c(int *esp); +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec); +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat); + +/* memory.c */ +#define MEMMAN_FREES 4090 /* ����Ŗ�32KB */ +#define MEMMAN_ADDR 0x003c0000 +struct FREEINFO { /* ������� */ + unsigned int addr, size; +}; +struct MEMMAN { /* �������Ǘ� */ + int frees, maxfrees, lostsize, losts; + struct FREEINFO free[MEMMAN_FREES]; +}; +unsigned int memtest(unsigned int start, unsigned int end); +void memman_init(struct MEMMAN *man); +unsigned int memman_total(struct MEMMAN *man); +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size); +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size); +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size); +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size); + +/* sheet.c */ +#define MAX_SHEETS 256 +struct SHEET { + unsigned char *buf; + int bxsize, bysize, vx0, vy0, col_inv, height, flags; + struct SHTCTL *ctl; + struct TASK *task; +}; +struct SHTCTL { + unsigned char *vram, *map; + int xsize, ysize, top; + struct SHEET *sheets[MAX_SHEETS]; + struct SHEET sheets0[MAX_SHEETS]; +}; +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize); +struct SHEET *sheet_alloc(struct SHTCTL *ctl); +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv); +void sheet_updown(struct SHEET *sht, int height); +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1); +void sheet_slide(struct SHEET *sht, int vx0, int vy0); +void sheet_free(struct SHEET *sht); + +/* timer.c */ +#define MAX_TIMER 500 +struct TIMER { + struct TIMER *next; + unsigned int timeout; + char flags, flags2; + struct FIFO32 *fifo; + int data; +}; +struct TIMERCTL { + unsigned int count, next; + struct TIMER *t0; + struct TIMER timers0[MAX_TIMER]; +}; +extern struct TIMERCTL timerctl; +void init_pit(void); +struct TIMER *timer_alloc(void); +void timer_free(struct TIMER *timer); +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data); +void timer_settime(struct TIMER *timer, unsigned int timeout); +void inthandler20(int *esp); +int timer_cancel(struct TIMER *timer); +void timer_cancelall(struct FIFO32 *fifo); + +/* mtask.c */ +#define MAX_TASKS 1000 /*最大任务数量*/ +#define TASK_GDT0 3 /*定义从GDT的几号开始分配给TSS */ +#define MAX_TASKS_LV 100 +#define MAX_TASKLEVELS 10 +struct TSS32 { + int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3; + int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi; + int es, cs, ss, ds, fs, gs; + int ldtr, iomap; +}; +struct TASK { + int sel, flags; /* sel用来存放GDT的编号*/ + int level, priority; /* 优先级 */ + struct FIFO32 fifo; + struct TSS32 tss; + struct SEGMENT_DESCRIPTOR ldt[2]; + struct CONSOLE *cons; + int ds_base, cons_stack; + struct FILEHANDLE *fhandle; + int *fat; + char *cmdline; + unsigned char langmode, langbyte1; +}; +struct TASKLEVEL { + int running; /*正在运行的任务数量*/ + int now; /*这个变量用来记录当前正在运行的是哪个任务*/ + struct TASK *tasks[MAX_TASKS_LV]; +}; +struct TASKCTL { + int now_lv; /*现在活动中的LEVEL */ + char lv_change; /*在下次任务切换时是否需要改变LEVEL */ + struct TASKLEVEL level[MAX_TASKLEVELS]; + struct TASK tasks0[MAX_TASKS]; +}; +extern struct TASKCTL *taskctl; +extern struct TIMER *task_timer; +struct TASK *task_now(void); +struct TASK *task_init(struct MEMMAN *memman); +struct TASK *task_alloc(void); +void task_run(struct TASK *task, int level, int priority); +void task_switch(void); +void task_sleep(struct TASK *task); + +/* window.c */ +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act); +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l); +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c); +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act); +void change_wtitle8(struct SHEET *sht, char act); + +/* console.c */ +struct CONSOLE { + struct SHEET *sht; + int cur_x, cur_y, cur_c; + struct TIMER *timer; +}; +struct FILEHANDLE { + char *buf; + int size; + int pos; +}; +void console_task(struct SHEET *sheet, int memtotal); +void cons_putchar(struct CONSOLE *cons, int chr, char move); +void cons_newline(struct CONSOLE *cons); +void cons_putstr0(struct CONSOLE *cons, char *s); +void cons_putstr1(struct CONSOLE *cons, char *s, int l); +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal); +void cmd_mem(struct CONSOLE *cons, int memtotal); +void cmd_cls(struct CONSOLE *cons); +void cmd_dir(struct CONSOLE *cons); +void cmd_exit(struct CONSOLE *cons, int *fat); +void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal); +void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal); +void cmd_langmode(struct CONSOLE *cons, char *cmdline); +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline); +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax); +int *inthandler0d(int *esp); +int *inthandler0c(int *esp); +void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col); + +/* file.c */ +struct FILEINFO { + unsigned char name[8], ext[3], type; + char reserve[10]; + unsigned short time, date, clustno; + unsigned int size; +}; +void file_readfat(int *fat, unsigned char *img); +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img); +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max); +char *file_loadfile2(int clustno, int *psize, int *fat); + +/* bootpack.c */ +struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal); +struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal); + +/* tek.c */ +int tek_getsize(unsigned char *p); +int tek_decomp(unsigned char *p, char *q, int size); diff --git a/30_day/haribote/console.c b/30_day/haribote/console.c new file mode 100644 index 0000000..3e51686 --- /dev/null +++ b/30_day/haribote/console.c @@ -0,0 +1,708 @@ +/* 命令行窗口相关 */ + +#include "bootpack.h" +#include +#include + +void console_task(struct SHEET *sheet, int memtotal) +{ + struct TASK *task = task_now(); + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + int i, *fat = (int *) memman_alloc_4k(memman, 4 * 2880); + struct FILEHANDLE fhandle[8]; + struct CONSOLE cons; + char cmdline[30]; + unsigned char *nihongo = (char *) *((int *) 0x0fe8); + + cons.sht = sheet; + cons.cur_x = 8; + cons.cur_y = 28; + cons.cur_c = -1; + task->cons = &cons; + task->cmdline = cmdline; + + if (cons.sht != 0) { + cons.timer = timer_alloc(); + timer_init(cons.timer, &task->fifo, 1); + timer_settime(cons.timer, 50); + } + file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200)); + for (i = 0; i < 8; i++) { + fhandle[i].buf = 0; /*未使用标记*/ + } + task->fhandle = fhandle; + task->fat = fat; + if (nihongo[4096] != 0xff) { /* 是否载入了字库?*/ + task->langmode = 1; + } else { + task->langmode = 0; + } + task->langbyte1 = 0; + + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + task_sleep(task); + io_sti(); + } else { + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1 && cons.sht != 0) { /*光标用定时器*/ + if (i != 0) { + timer_init(cons.timer, &task->fifo, 0); /*下次置0 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_FFFFFF; + } + } else { + timer_init(cons.timer, &task->fifo, 1); /*下次置1 */ + if (cons.cur_c >= 0) { + cons.cur_c = COL8_000000; + } + } + timer_settime(cons.timer, 50); + } + if (i == 2) { /*光标ON */ + cons.cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + if (cons.sht != 0) { + boxfill8(cons.sht->buf, cons.sht->bxsize, COL8_000000, + cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + } + cons.cur_c = -1; + } + if (i == 4) { /*点击命令行窗口的“×”按钮*/ + cmd_exit(&cons, fat); + } + if (256 <= i && i <= 511) { /*键盘数据(通过任务A)*/ + if (i == 8 + 256) { + /*退格键*/ + if (cons.cur_x > 16) { + /*用空格擦除光标后将光标前移一位*/ + cons_putchar(&cons, ' ', 0); + cons.cur_x -= 8; + } + } else if (i == 10 + 256) { + /*回车键*/ + /*将光标用空格擦除后换行 */ + cons_putchar(&cons, ' ', 0); + cmdline[cons.cur_x / 8 - 2] = 0; + cons_newline(&cons); + cons_runcmd(cmdline, &cons, fat, memtotal); /*运行命令*/ + if (cons.sht == 0) { + cmd_exit(&cons, fat); + } + /*显示提示符*/ + cons_putchar(&cons, '>', 1); + } else { + /*一般字符*/ + if (cons.cur_x < 240) { + /*显示一个字符之后将光标后移一位*/ + cmdline[cons.cur_x / 8 - 2] = i - 256; + cons_putchar(&cons, i - 256, 1); + } + } + } + /*重新显示光标*/ + if (cons.sht != 0) { + if (cons.cur_c >= 0) { + boxfill8(cons.sht->buf, cons.sht->bxsize, cons.cur_c, + cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15); + } + sheet_refresh(cons.sht, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16); + } + } + } +} + +void cons_putchar(struct CONSOLE *cons, int chr, char move) +{ + char s[2]; + s[0] = chr; + s[1] = 0; + if (s[0] == 0x09) { /*制表符*/ + for (;;) { + if (cons->sht != 0) { + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1); + } + cons->cur_x += 8; + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + if (((cons->cur_x - 8) & 0x1f) == 0) { + break; /*被32整除则break*/ + } + } + } else if (s[0] == 0x0a) { /*换行*/ + cons_newline(cons); + } else if (s[0] == 0x0d) { /*回车*/ + /*先不做任何操作*/ + } else { /*一般字符*/ + if (cons->sht != 0) { + putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1); + } + if (move != 0) { + /* move为0时光标不后移*/ + cons->cur_x += 8; + if (cons->cur_x == 8 + 240) { + cons_newline(cons); + } + } + } + return; +} + +void cons_newline(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + struct TASK *task = task_now(); + if (cons->cur_y < 28 + 112) { + cons->cur_y += 16; /*到下一行*/ + } else { + /*滚动*/ + if (sheet != 0) { + for (y = 28; y < 28 + 112; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize]; + } + } + for (y = 28 + 112; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + } + } + cons->cur_x = 8; + if (task->langmode == 1 && task->langbyte1 != 0) { + cons->cur_x += 8; + } + return; +} + +void cons_putstr0(struct CONSOLE *cons, char *s) +{ + for (; *s != 0; s++) { + cons_putchar(cons, *s, 1); + } + return; +} + +void cons_putstr1(struct CONSOLE *cons, char *s, int l) +{ + int i; + for (i = 0; i < l; i++) { + cons_putchar(cons, s[i], 1); + } + return; +} + +void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) +{ + if (strcmp(cmdline, "mem") == 0 && cons->sht != 0) { + cmd_mem(cons, memtotal); + } else if (strcmp(cmdline, "cls") == 0 && cons->sht != 0) { + cmd_cls(cons); + } else if ((strcmp(cmdline, "dir") == 0 || strcmp(cmdline, "ls") == 0) && cons->sht != 0) { + cmd_dir(cons); + } else if (strcmp(cmdline, "exit") == 0) { + cmd_exit(cons, fat); + } else if (strncmp(cmdline, "start ", 6) == 0) { + cmd_start(cons, cmdline, memtotal); + } else if (strncmp(cmdline, "ncst ", 5) == 0) { + cmd_ncst(cons, cmdline, memtotal); + } else if (strncmp(cmdline, "langmode ", 9) == 0) { + cmd_langmode(cons, cmdline); + }else if (cmdline[0] != 0) { + if (cmd_app(cons, fat, cmdline) == 0) { + /*不是命令,不是应用程序,也不是空行*/ + cons_putstr0(cons, "Bad command.\n\n"); + } + } + return; +} + +void cmd_mem(struct CONSOLE *cons, int memtotal) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + char s[60]; + sprintf(s, "total %dMB\nfree %dKB\n\n", memtotal / (1024 * 1024), memman_total(memman) / 1024); + cons_putstr0(cons, s); + return; +} + +void cmd_cls(struct CONSOLE *cons) +{ + int x, y; + struct SHEET *sheet = cons->sht; + for (y = 28; y < 28 + 128; y++) { + for (x = 8; x < 8 + 240; x++) { + sheet->buf[x + y * sheet->bxsize] = COL8_000000; + } + } + sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); + cons->cur_y = 28; + return; +} + +void cmd_dir(struct CONSOLE *cons) +{ + struct FILEINFO *finfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600); + int i, j; + char s[30]; + for (i = 0; i < 224; i++) { + if (finfo[i].name[0] == 0x00) { + break; + } + if (finfo[i].name[0] != 0xe5) { + if ((finfo[i].type & 0x18) == 0) { + sprintf(s, "filename.ext %7d\n", finfo[i].size); + for (j = 0; j < 8; j++) { + s[j] = finfo[i].name[j]; + } + s[ 9] = finfo[i].ext[0]; + s[10] = finfo[i].ext[1]; + s[11] = finfo[i].ext[2]; + cons_putstr0(cons, s); + } + } + } + cons_newline(cons); + return; +} + +void cmd_exit(struct CONSOLE *cons, int *fat) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct TASK *task = task_now(); + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct FIFO32 *fifo = (struct FIFO32 *) *((int *) 0x0fec); + if (cons->sht != 0) { + timer_cancel(cons->timer); + } + memman_free_4k(memman, (int) fat, 4 * 2880); + io_cli(); + if (cons->sht != 0) { + fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); /* 768〜1023 */ + } else { + fifo32_put(fifo, task - taskctl->tasks0 + 1024); /*1024~2023*/ + } + io_sti(); + for (;;) { + task_sleep(task); + } +} + +void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal) +{ + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct SHEET *sht = open_console(shtctl, memtotal); + struct FIFO32 *fifo = &sht->task->fifo; + int i; + sheet_slide(sht, 32, 4); + sheet_updown(sht, shtctl->top); + /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ + for (i = 6; cmdline[i] != 0; i++) { + fifo32_put(fifo, cmdline[i] + 256); + } + fifo32_put(fifo, 10 + 256); /*回车键*/ + cons_newline(cons); + return; +} + +void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal) +{ + struct TASK *task = open_constask(0, memtotal); + struct FIFO32 *fifo = &task->fifo; + int i; + + /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ + for (i = 5; cmdline[i] != 0; i++) { + fifo32_put(fifo, cmdline[i] + 256); + } + fifo32_put(fifo, 10 + 256); /*回车键*/ + cons_newline(cons); + return; +} + +void cmd_langmode(struct CONSOLE *cons, char *cmdline) +{ + struct TASK *task = task_now(); + unsigned char mode = cmdline[9] - '0'; + if (mode <= 2) { + task->langmode = mode; + } else { + cons_putstr0(cons, "mode number error.\n"); + } + cons_newline(cons); + return; +} + +int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) +{ + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + struct FILEINFO *finfo; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + char name[18], *p, *q; + struct TASK *task = task_now(); + int i, segsiz, datsiz, esp, dathrb, appsiz; + struct SHTCTL *shtctl; + struct SHEET *sht; + + /*根据命令行生成文件名*/ + for (i = 0; i < 13; i++) { + if (cmdline[i] <= ' ') { + break; + } + name[i] = cmdline[i]; + } + name[i] = 0; /*暂且将文件名的后面置为0*/ + + /*寻找文件 */ + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + if (finfo == 0 && name[i - 1] != '.') { + /*由于找不到文件,故在文件名后面加上“.hrb”后重新寻找*/ + name[i ] = '.'; + name[i + 1] = 'H'; + name[i + 2] = 'R'; + name[i + 3] = 'B'; + name[i + 4] = 0; + finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + } + + if (finfo != 0) { + /*如果找到文件*/ + appsiz = finfo->size; + p = file_loadfile2(finfo->clustno, &appsiz, fat); + if (appsiz >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) { + segsiz = *((int *) (p + 0x0000)); + esp = *((int *) (p + 0x000c)); + datsiz = *((int *) (p + 0x0010)); + dathrb = *((int *) (p + 0x0014)); + q = (char *) memman_alloc_4k(memman, segsiz); + task->ds_base = (int) q; + set_segmdesc(task->ldt + 0, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); + set_segmdesc(task->ldt + 1, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); + for (i = 0; i < datsiz; i++) { + q[esp + i] = p[dathrb + i]; + } + start_app(0x1b, 0 * 8 + 4, esp, 1 * 8 + 4, &(task->tss.esp0)); + shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + for (i = 0; i < MAX_SHEETS; i++) { + sht = &(shtctl->sheets0[i]); + if ((sht->flags & 0x11) == 0x11 && sht->task == task) { + /*找到被应用程序遗留的窗口*/ + sheet_free(sht); /*关闭*/ + } + } + for (i = 0; i < 8; i++) { /*将未关闭的文件关闭*/ + if (task->fhandle[i].buf != 0) { + memman_free_4k(memman, (int) task->fhandle[i].buf, task->fhandle[i].size); + task->fhandle[i].buf = 0; + } + } + timer_cancelall(&task->fifo); + memman_free_4k(memman, (int) q, segsiz); + task->langbyte1 = 0; + } else { + cons_putstr0(cons, ".hrb file format error.\n"); + } + memman_free_4k(memman, (int) p, appsiz); + cons_newline(cons); + return 1; + } + /*没有找到文件的情况*/ + return 0; +} + +int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) +{ + struct TASK *task = task_now(); + int ds_base = task->ds_base; + struct CONSOLE *cons = task->cons; + struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); + struct SHEET *sht; + struct FIFO32 *sys_fifo = (struct FIFO32 *) *((int *) 0x0fec); + int *reg = &eax + 1; /* eax后面的地址*/ + /*强行改写通过PUSHAD保存的值*/ + /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */ + /* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ + int i; + struct FILEINFO *finfo; + struct FILEHANDLE *fh; + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + + if (edx == 1) { + cons_putchar(cons, eax & 0xff, 1); + } else if (edx == 2) { + cons_putstr0(cons, (char *) ebx + ds_base); + } else if (edx == 3) { + cons_putstr1(cons, (char *) ebx + ds_base, ecx); + } else if (edx == 4) { + return &(task->tss.esp0); + } else if (edx == 5) { + sht = sheet_alloc(shtctl); + sht->task = task; + sht->flags |= 0x10; + sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax); + make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0); + sheet_slide(sht, ((shtctl->xsize - esi) / 2) & ~3, (shtctl->ysize - edi) / 2); + sheet_updown(sht, shtctl->top); /*将窗口图层高度指定为当前鼠标所在图层的高度,鼠标移到上层*/ + reg[7] = (int) sht; + } else if (edx == 6) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + putfonts8_asc(sht->buf, sht->bxsize, esi, edi, eax, (char *) ebp + ds_base); + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + ecx * 8, edi + 16); + } + } else if (edx == 7) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + boxfill8(sht->buf, sht->bxsize, ebp, eax, ecx, esi, edi); + if ((ebx & 1) == 0) { + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 8) { + memman_init((struct MEMMAN *) (ebx + ds_base)); + ecx &= 0xfffffff0; /*以16字节为单位*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 9) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + reg[7] = memman_alloc((struct MEMMAN *) (ebx + ds_base), ecx); + } else if (edx == 10) { + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); + } else if (edx == 11) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + sht->buf[sht->bxsize * edi + esi] = eax; + if ((ebx & 1) == 0) { + sheet_refresh(sht, esi, edi, esi + 1, edi + 1); + } + } else if (edx == 12) { + sht = (struct SHEET *) ebx; + sheet_refresh(sht, eax, ecx, esi, edi); + } else if (edx == 13) { + sht = (struct SHEET *) (ebx & 0xfffffffe); + hrb_api_linewin(sht, eax, ecx, esi, edi, ebp); + if ((ebx & 1) == 0) { + if (eax > esi) { + i = eax; + eax = esi; + esi = i; + } + if (ecx > edi) { + i = ecx; + ecx = edi; + edi = i; + } + sheet_refresh(sht, eax, ecx, esi + 1, edi + 1); + } + } else if (edx == 14) { + sheet_free((struct SHEET *) ebx); + } else if (edx == 15) { + for (;;) { + io_cli(); + if (fifo32_status(&task->fifo) == 0) { + if (eax != 0) { + task_sleep(task); /* FIFO为空,休眠并等待*/ + } else { + io_sti(); + reg[7] = -1; + return 0; + } + } + i = fifo32_get(&task->fifo); + io_sti(); + if (i <= 1) { /*光标用定时器*/ + /*应用程序运行时不需要显示光标,因此总是将下次显示用的值置为1*/ + timer_init(cons->timer, &task->fifo, 1); /*下次置为1*/ + timer_settime(cons->timer, 50); + } + if (i == 2) { /*光标ON */ + cons->cur_c = COL8_FFFFFF; + } + if (i == 3) { /*光标OFF */ + cons->cur_c = -1; + } + if (i == 4) { /*只关闭命令行窗口*/ + timer_cancel(cons->timer); + io_cli(); + fifo32_put(sys_fifo, cons->sht - shtctl->sheets0 + 2024); /*2024~2279*/ + cons->sht = 0; + io_sti(); + } + if (i >= 256) { /*键盘数据(通过任务A)等*/ + reg[7] = i - 256; + return 0; + } + } + } else if (edx == 16) { + reg[7] = (int) timer_alloc(); + ((struct TIMER *) reg[7])->flags2 = 1; /*允许自动取消*/ + } else if (edx == 17) { + timer_init((struct TIMER *) ebx, &task->fifo, eax + 256); + } else if (edx == 18) { + timer_settime((struct TIMER *) ebx, eax); + } else if (edx == 19) { + timer_free((struct TIMER *) ebx); + } else if (edx == 20) { + if (eax == 0) { + i = io_in8(0x61); + io_out8(0x61, i & 0x0d); + } else { + i = 1193180000 / eax; + io_out8(0x43, 0xb6); + io_out8(0x42, i & 0xff); + io_out8(0x42, i >> 8); + i = io_in8(0x61); + io_out8(0x61, (i | 0x03) & 0x0f); + } + } else if (edx == 21) { + for (i = 0; i < 8; i++) { + if (task->fhandle[i].buf == 0) { + break; + } + } + fh = &task->fhandle[i]; + reg[7] = 0; + if (i < 8) { + finfo = file_search((char *) ebx + ds_base, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + if (finfo != 0) { + reg[7] = (int) fh; + fh->buf = (char *) memman_alloc_4k(memman, finfo->size); + fh->size = finfo->size; + fh->pos = 0; + file_loadfile2(finfo->clustno, &fh->size, task->fat); + } + } + } else if (edx == 22) { + fh = (struct FILEHANDLE *) eax; + memman_free_4k(memman, (int) fh->buf, fh->size); + fh->buf = 0; + } else if (edx == 23) { + fh = (struct FILEHANDLE *) eax; + if (ecx == 0) { + fh->pos = ebx; + } else if (ecx == 1) { + fh->pos += ebx; + } else if (ecx == 2) { + fh->pos = fh->size + ebx; + } + if (fh->pos < 0) { + fh->pos = 0; + } + if (fh->pos > fh->size) { + fh->pos = fh->size; + } + } else if (edx == 24) { + fh = (struct FILEHANDLE *) eax; + if (ecx == 0) { + reg[7] = fh->size; + } else if (ecx == 1) { + reg[7] = fh->pos; + } else if (ecx == 2) { + reg[7] = fh->pos - fh->size; + } + } else if (edx == 25) { + fh = (struct FILEHANDLE *) eax; + for (i = 0; i < ecx; i++) { + if (fh->pos == fh->size) { + break; + } + *((char *) ebx + ds_base + i) = fh->buf[fh->pos]; + fh->pos++; + } + reg[7] = i; + } else if (edx == 26) { + i = 0; + for (;;) { + *((char *) ebx + ds_base + i) = task->cmdline[i]; + if (task->cmdline[i] == 0) { + break; + } + if (i >= ecx) { + break; + } + i++; + } + reg[7] = i; + } else if (edx == 27) { + reg[7] = task->langmode; + } + return 0; +} + +int *inthandler0c(int *esp) +{ + struct TASK *task = task_now(); + struct CONSOLE *cons = task->cons; + char s[30]; + cons_putstr0(cons, "\nINT 0C :\n Stack Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +int *inthandler0d(int *esp) +{ + struct TASK *task = task_now(); + struct CONSOLE *cons = task->cons; + char s[30]; + cons_putstr0(cons, "\nINT 0D :\n General Protected Exception.\n"); + sprintf(s, "EIP = %08X\n", esp[11]); + cons_putstr0(cons, s); + return &(task->tss.esp0); /*强制结束程序*/ +} + +void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col) +{ + int i, x, y, len, dx, dy; + + dx = x1 - x0; + dy = y1 - y0; + x = x0 << 10; + y = y0 << 10; + if (dx < 0) { + dx = - dx; + } + if (dy < 0) { + dy = - dy; + } + if (dx >= dy) { + len = dx + 1; + if (x0 > x1) { + dx = -1024; + } else { + dx = 1024; + } + if (y0 <= y1) { + dy = ((y1 - y0 + 1) << 10) / len; + } else { + dy = ((y1 - y0 - 1) << 10) / len; + } + } else { + len = dy + 1; + if (y0 > y1) { + dy = -1024; + } else { + dy = 1024; + } + if (x0 <= x1) { + dx = ((x1 - x0 + 1) << 10) / len; + } else { + dx = ((x1 - x0 - 1) << 10) / len; + } + } + + for (i = 0; i < len; i++) { + sht->buf[(y >> 10) * sht->bxsize + (x >> 10)] = col; + x += dx; + y += dy; + } + + return; +} diff --git a/30_day/haribote/dsctbl.c b/30_day/haribote/dsctbl.c new file mode 100644 index 0000000..9ff2c67 --- /dev/null +++ b/30_day/haribote/dsctbl.c @@ -0,0 +1,59 @@ +/* GDT、IDT、descriptor table 关系处理 */ + +#include "bootpack.h" + +void init_gdtidt(void) +{ + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *) ADR_IDT; + int i; + + /* GDT初始化 */ + for (i = 0; i <= LIMIT_GDT / 8; i++) { + set_segmdesc(gdt + i, 0, 0, 0); + } + set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW); + set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER); + load_gdtr(LIMIT_GDT, ADR_GDT); + + /* IDT初始化 */ + for (i = 0; i <= LIMIT_IDT / 8; i++) { + set_gatedesc(idt + i, 0, 0, 0); + } + load_idtr(LIMIT_IDT, ADR_IDT); + + /* IDT设置*/ + set_gatedesc(idt + 0x0c, (int) asm_inthandler0c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x0d, (int) asm_inthandler0d, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32); + set_gatedesc(idt + 0x40, (int) asm_hrb_api, 2 * 8, AR_INTGATE32 + 0x60); + + return; +} + +void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar) +{ + if (limit > 0xfffff) { + ar |= 0x8000; /* G_bit = 1 */ + limit /= 0x1000; + } + sd->limit_low = limit & 0xffff; + sd->base_low = base & 0xffff; + sd->base_mid = (base >> 16) & 0xff; + sd->access_right = ar & 0xff; + sd->limit_high = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0); + sd->base_high = (base >> 24) & 0xff; + return; +} + +void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar) +{ + gd->offset_low = offset & 0xffff; + gd->selector = selector; + gd->dw_count = (ar >> 8) & 0xff; + gd->access_right = ar & 0xff; + gd->offset_high = (offset >> 16) & 0xffff; + return; +} diff --git a/30_day/haribote/fifo.c b/30_day/haribote/fifo.c new file mode 100644 index 0000000..8f28f4b --- /dev/null +++ b/30_day/haribote/fifo.c @@ -0,0 +1,63 @@ +/* FIFO */ + +#include "bootpack.h" + +#define FLAGS_OVERRUN 0x0001 + +void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task) +/* FIFO缓冲区的初始化*/ +{ + fifo->size = size; + fifo->buf = buf; + fifo->free = size; /*空*/ + fifo->flags = 0; + fifo->p = 0; /*写入位置*/ + fifo->q = 0; /*读取位置*/ + fifo->task = task; /*有数据写入时需要唤醒的任务*/ + return; +} + +int fifo32_put(struct FIFO32 *fifo, int data) +/*向FIFO写入数据并累积起来*/ +{ + if (fifo->free == 0) { + /*没有空余空间,溢出*/ + fifo->flags |= FLAGS_OVERRUN; + return -1; + } + fifo->buf[fifo->p] = data; + fifo->p++; + if (fifo->p == fifo->size) { + fifo->p = 0; + } + fifo->free--; + if (fifo->task != 0) { + if (fifo->task->flags != 2) { /*如果任务处于休眠状态*/ + task_run(fifo->task, -1, 0); /*将任务唤醒*/ + } + } + return 0; +} + +int fifo32_get(struct FIFO32 *fifo) +/*从FIFO取得一个数据*/ +{ + int data; + if (fifo->free == fifo->size) { + /*当缓冲区为空的情况下返回-1*/ + return -1; + } + data = fifo->buf[fifo->q]; + fifo->q++; + if (fifo->q == fifo->size) { + fifo->q = 0; + } + fifo->free++; + return data; +} + +int fifo32_status(struct FIFO32 *fifo) +/*报告已经存储了多少数据*/ +{ + return fifo->size - fifo->free; +} diff --git a/30_day/haribote/file.c b/30_day/haribote/file.c new file mode 100644 index 0000000..a4bf405 --- /dev/null +++ b/30_day/haribote/file.c @@ -0,0 +1,94 @@ +/* 文件相关函数 */ + +#include "bootpack.h" + +void file_readfat(int *fat, unsigned char *img) +/*将磁盘映像中的FAT解压缩 */ +{ + int i, j = 0; + for (i = 0; i < 2880; i += 2) { + fat[i + 0] = (img[j + 0] | img[j + 1] << 8) & 0xfff; + fat[i + 1] = (img[j + 1] >> 4 | img[j + 2] << 4) & 0xfff; + j += 3; + } + return; +} + +void file_loadfile(int clustno, int size, char *buf, int *fat, char *img) +{ + int i; + for (;;) { + if (size <= 512) { + for (i = 0; i < size; i++) { + buf[i] = img[clustno * 512 + i]; + } + break; + } + for (i = 0; i < 512; i++) { + buf[i] = img[clustno * 512 + i]; + } + size -= 512; + buf += 512; + clustno = fat[clustno]; + } + return; +} + +struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max) +{ + int i, j; + char s[12]; + for (j = 0; j < 11; j++) { + s[j] = ' '; + } + j = 0; + for (i = 0; name[i] != 0; i++) { + if (j >= 11) { return 0; /*没有找到*/ } + if (name[i] == '.' && j <= 8) { + j = 8; + } else { + s[j] = name[i]; + if ('a' <= s[j] && s[j] <= 'z') { + /*将小写字母转换为大写字母*/ + s[j] -= 0x20; + } + j++; + } + } + for (i = 0; i < max; ) { + if (finfo->name[0] == 0x00) { + break; + } + if ((finfo[i].type & 0x18) == 0) { + for (j = 0; j < 11; j++) { + if (finfo[i].name[j] != s[j]) { + goto next; + } + } + return finfo + i; /*找到文件*/ + } +next: + i++; + } + return 0; /*没有找到*/ +} + +char *file_loadfile2(int clustno, int *psize, int *fat) +{ + int size = *psize, size2; + struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; + char *buf, *buf2; + buf = (char *) memman_alloc_4k(memman, size); + file_loadfile(clustno, size, buf, fat, (char *) (ADR_DISKIMG + 0x003e00)); + if (size >= 17) { + size2 = tek_getsize(buf); + if (size2 > 0) { /*使用tek格式压缩的文件*/ + buf2 = (char *) memman_alloc_4k(memman, size2); + tek_decomp(buf, buf2, size2); + memman_free_4k(memman, (int) buf, size); + buf = buf2; + *psize = size2; + } + } + return buf; +} diff --git a/30_day/haribote/graphic.c b/30_day/haribote/graphic.c new file mode 100644 index 0000000..3ac5000 --- /dev/null +++ b/30_day/haribote/graphic.c @@ -0,0 +1,221 @@ +/* 关于绘图部分的处理 */ + +#include "bootpack.h" + +void init_palette(void) +{ + static unsigned char table_rgb[16 * 3] = { + 0x00, 0x00, 0x00, /* 0:黑 */ + 0xff, 0x00, 0x00, /* 1:梁红 */ + 0x00, 0xff, 0x00, /* 2:亮绿 */ + 0xff, 0xff, 0x00, /* 3:亮黄 */ + 0x00, 0x00, 0xff, /* 4:亮蓝 */ + 0xff, 0x00, 0xff, /* 5:亮紫 */ + 0x00, 0xff, 0xff, /* 6:浅亮蓝 */ + 0xff, 0xff, 0xff, /* 7:白 */ + 0xc6, 0xc6, 0xc6, /* 8:亮灰 */ + 0x84, 0x00, 0x00, /* 9:暗红 */ + 0x00, 0x84, 0x00, /* 10:暗绿 */ + 0x84, 0x84, 0x00, /* 11:暗黄 */ + 0x00, 0x00, 0x84, /* 12:暗青 */ + 0x84, 0x00, 0x84, /* 13:暗紫 */ + 0x00, 0x84, 0x84, /* 14:浅暗蓝 */ + 0x84, 0x84, 0x84 /* 15:暗灰 */ + }; + unsigned char table2[216 * 3]; + int r, g, b; + set_palette(0, 15, table_rgb); + for (b = 0; b < 6; b++) { + for (g = 0; g < 6; g++) { + for (r = 0; r < 6; r++) { + table2[(r + g * 6 + b * 36) * 3 + 0] = r * 51; + table2[(r + g * 6 + b * 36) * 3 + 1] = g * 51; + table2[(r + g * 6 + b * 36) * 3 + 2] = b * 51; + } + } + } + set_palette(16, 231, table2); + return; +} + +void set_palette(int start, int end, unsigned char *rgb) +{ + int i, eflags; + eflags = io_load_eflags(); /* 记录中断许可标志的值 */ + io_cli(); /* 将中断许可标志置为0,禁止中断 */ + io_out8(0x03c8, start); + for (i = start; i <= end; i++) { + io_out8(0x03c9, rgb[0] / 4); + io_out8(0x03c9, rgb[1] / 4); + io_out8(0x03c9, rgb[2] / 4); + rgb += 3; + } + io_store_eflags(eflags); /* 复原中断许可标志 */ + return; +} + +void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) +{ + int x, y; + for (y = y0; y <= y1; y++) { + for (x = x0; x <= x1; x++) + vram[y * xsize + x] = c; + } + return; +} + +void init_screen8(char *vram, int x, int y) +{ + boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28); + boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27); + boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1); + + boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24); + boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4); + boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4); + boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5); + boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3); + boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3); + + boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24); + boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4); + boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3); + boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3); + return; +} + +void putfont8(char *vram, int xsize, int x, int y, char c, char *font) +{ + int i; + char *p, d /* data */; + for (i = 0; i < 16; i++) { + p = vram + (y + i) * xsize + x; + d = font[i]; + if ((d & 0x80) != 0) { p[0] = c; } + if ((d & 0x40) != 0) { p[1] = c; } + if ((d & 0x20) != 0) { p[2] = c; } + if ((d & 0x10) != 0) { p[3] = c; } + if ((d & 0x08) != 0) { p[4] = c; } + if ((d & 0x04) != 0) { p[5] = c; } + if ((d & 0x02) != 0) { p[6] = c; } + if ((d & 0x01) != 0) { p[7] = c; } + } + return; +} + +void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s) +{ + extern char hankaku[4096]; + struct TASK *task = task_now(); + char *nihongo = (char *) *((int *) 0x0fe8), *font; + int k, t; + + if (task->langmode == 0) { + for (; *s != 0x00; s++) { + putfont8(vram, xsize, x, y, c, hankaku + *s * 16); + x += 8; + } + } + if (task->langmode == 1) { + for (; *s != 0x00; s++) { + if (task->langbyte1 == 0) { + if ((0x81 <= *s && *s <= 0x9f) || (0xe0 <= *s && *s <= 0xfc)) { + task->langbyte1 = *s; + } else { + putfont8(vram, xsize, x, y, c, nihongo + *s * 16); + } + } else { + if (0x81 <= task->langbyte1 && task->langbyte1 <= 0x9f) { + k = (task->langbyte1 - 0x81) * 2; + } else { + k = (task->langbyte1 - 0xe0) * 2 + 62; + } + if (0x40 <= *s && *s <= 0x7e) { + t = *s - 0x40; + } else if (0x80 <= *s && *s <= 0x9e) { + t = *s - 0x80 + 63; + } else { + t = *s - 0x9f; + k++; + } + task->langbyte1 = 0; + font = nihongo + 256 * 16 + (k * 94 + t) * 32; + putfont8(vram, xsize, x - 8, y, c, font ); /* 左半部分 */ + putfont8(vram, xsize, x , y, c, font + 16); /* 右半部分 */ + } + x += 8; + } + } + if (task->langmode == 2) { + for (; *s != 0x00; s++) { + if (task->langbyte1 == 0) { + if (0x81 <= *s && *s <= 0xfe) { + task->langbyte1 = *s; + } else { + putfont8(vram, xsize, x, y, c, nihongo + *s * 16); + } + } else { + k = task->langbyte1 - 0xa1; + t = *s - 0xa1; + task->langbyte1 = 0; + font = nihongo + 256 * 16 + (k * 94 + t) * 32; + putfont8(vram, xsize, x - 8, y, c, font ); /* 左半部分 */ + putfont8(vram, xsize, x , y, c, font + 16); /* 右半部分 */ + } + x += 8; + } + } + return; +} + +void init_mouse_cursor8(char *mouse, char bc) +/* 鼠标的数据准备(16x16) */ +{ + static char cursor[16][16] = { + "**************..", + "*OOOOOOOOOOO*...", + "*OOOOOOOOOO*....", + "*OOOOOOOOO*.....", + "*OOOOOOOO*......", + "*OOOOOOO*.......", + "*OOOOOOO*.......", + "*OOOOOOOO*......", + "*OOOO**OOO*.....", + "*OOO*..*OOO*....", + "*OO*....*OOO*...", + "*O*......*OOO*..", + "**........*OOO*.", + "*..........*OOO*", + "............*OO*", + ".............***" + }; + int x, y; + + for (y = 0; y < 16; y++) { + for (x = 0; x < 16; x++) { + if (cursor[y][x] == '*') { + mouse[y * 16 + x] = COL8_000000; + } + if (cursor[y][x] == 'O') { + mouse[y * 16 + x] = COL8_FFFFFF; + } + if (cursor[y][x] == '.') { + mouse[y * 16 + x] = bc; + } + } + } + return; +} + +void putblock8_8(char *vram, int vxsize, int pxsize, + int pysize, int px0, int py0, char *buf, int bxsize) +{ + int x, y; + for (y = 0; y < pysize; y++) { + for (x = 0; x < pxsize; x++) { + vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x]; + } + } + return; +} diff --git a/30_day/haribote/hankaku.txt b/30_day/haribote/hankaku.txt new file mode 100644 index 0000000..62d56f9 --- /dev/null +++ b/30_day/haribote/hankaku.txt @@ -0,0 +1,4609 @@ +OSASK̔ptHg𗬗p + +char 0x00 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x01 +........ +........ +..***... +.*...*.. +*.....*. +*.*.*.*. +*.*.*.*. +*.....*. +*.....*. +*.*.*.*. +*..*..*. +.*...*.. +..***... +........ +........ +........ + +char 0x02 +........ +........ +..***... +.*****.. +*******. +**.*.**. +**.*.**. +*******. +*******. +**.*.**. +***.***. +.*****.. +..***... +........ +........ +........ + +char 0x03 +........ +........ +........ +........ +.**.**.. +*******. +*******. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x04 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +.*****.. +..***... +...*.... +........ +........ +........ +........ +........ + +char 0x05 +........ +........ +........ +........ +...*.... +..***... +.*.*.*.. +*******. +.*.*.*.. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x06 +........ +........ +........ +........ +...*.... +..***... +.*****.. +*******. +**.*.**. +...*.... +..***... +........ +........ +........ +........ +........ + +char 0x07 +........ +........ +........ +........ +........ +........ +...**... +..****.. +..****.. +...**... +........ +........ +........ +........ +........ +........ + +char 0x08 +******** +******** +******** +******** +******** +******** +***..*** +**....** +**....** +***..*** +******** +******** +******** +******** +******** +******** + +char 0x09 +........ +........ +........ +........ +........ +..****.. +.**..**. +.*....*. +.*....*. +.**..**. +..****.. +........ +........ +........ +........ +........ + +char 0x0a +******** +******** +******** +******** +******** +**....** +*..**..* +*.****.* +*.****.* +*..**..* +**....** +******** +******** +******** +******** +******** + +char 0x0b +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x0c +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ + +char 0x0d +........ +........ +....**.. +....***. +....*.** +....*.** +....*.*. +....*... +....*... +...**... +.****... +*****... +.***.... +........ +........ +........ + +char 0x0e +........ +........ +...***** +...***** +...*...* +...*...* +...*...* +...*...* +...*...* +...*...* +.***.*** +******** +.**..**. +........ +........ +........ + +char 0x0f +........ +........ +........ +........ +...*.... +.*.*.*.. +..***... +..*.*... +..***... +.*.*.*.. +...*.... +........ +........ +........ +........ +........ + +char 0x10 +........ +*....... +**...... +***..... +****.... +*****... +******.. +*******. +******.. +*****... +****.... +***..... +**...... +*....... +........ +........ + +char 0x11 +........ +......*. +.....**. +....***. +...****. +..*****. +.******. +*******. +.******. +..*****. +...****. +....***. +.....**. +......*. +........ +........ + +char 0x12 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ +........ + +char 0x13 +........ +........ +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +........ +........ +.*...*.. +.*...*.. +........ +........ + +char 0x14 +........ +..*****. +.*..*.*. +*...*.*. +*...*.*. +*...*.*. +*...*.*. +.*..*.*. +..***.*. +....*.*. +....*.*. +....*.*. +....*.*. +....*.*. +........ +........ + +char 0x15 +.*****.. +*.....*. +.*...... +..*..... +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +....*... +.....*.. +*.....*. +.*****.. +........ + +char 0x16 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*******. +*******. +........ +........ + +char 0x17 +........ +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +.*****.. +........ +........ + +char 0x18 +........ +...*.... +..***... +.*.*.*.. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x19 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +*..*..*. +.*.*.*.. +..***... +...*.... +........ +........ + +char 0x1a +........ +........ +........ +........ +...*.... +....*... +.....*.. +*******. +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ + +char 0x1b +........ +........ +........ +........ +...*.... +..*..... +.*...... +*******. +.*...... +..*..... +...*.... +........ +........ +........ +........ +........ + +char 0x1c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*....... +*....... +*******. +........ +........ + +char 0x1d +........ +........ +........ +........ +........ +..*.*... +.*...*.. +*******. +.*...*.. +..*.*... +........ +........ +........ +........ +........ +........ + +char 0x1e +........ +........ +........ +........ +...*.... +...*.... +..***... +..***... +.*****.. +.*****.. +*******. +*******. +........ +........ +........ +........ + +char 0x1f +........ +........ +........ +........ +*******. +*******. +.*****.. +.*****.. +..***... +..***... +...*.... +...*.... +........ +........ +........ +........ + +char 0x20 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x21 +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ +...*.... +...*.... +........ +........ + +char 0x22 +..*.*... +..*.*... +..*.*... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x23 +........ +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +.*...*.. +*******. +.*...*.. +.*...*.. +.*...*.. +........ +........ + +char 0x24 +...*.... +..***.*. +.*.*.**. +*..*..*. +*..*..*. +*..*.... +.*.*.... +..***... +...*.*.. +...*..*. +*..*..*. +*..*..*. +**.*.*.. +*.***... +...*.... +...*.... + +char 0x25 +.**...*. +*..*..*. +*..*.*.. +*..*.*.. +.**.*... +....*... +...*.... +...*.... +..*..... +..*.**.. +.*.*..*. +.*.*..*. +*..*..*. +*...**.. +........ +........ + +char 0x26 +........ +.***.... +*...*... +*...*... +*...*... +*..*.... +.**..... +.*...*** +*.*...*. +*..*..*. +*...*.*. +*....*.. +.*...**. +..***..* +........ +........ + +char 0x27 +.....*.. +....*... +...*.... +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x28 +......*. +.....*.. +....*... +....*... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....*... +....*... +.....*.. +......*. +........ + +char 0x29 +*....... +.*...... +..*..... +..*..... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..*..... +..*..... +.*...... +*....... +........ + +char 0x2a +........ +........ +........ +........ +........ +...*.... +*..*..*. +.*.*.*.. +..***... +.*.*.*.. +*..*..*. +...*.... +........ +........ +........ +........ + +char 0x2b +........ +........ +........ +........ +........ +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +........ +........ +........ +........ + +char 0x2c +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x2d +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ +........ +........ +........ +........ +........ +........ + +char 0x2e +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x2f +......*. +......*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*...... +.*...... +*....... +*....... + +char 0x30 +........ +...**... +..*..*.. +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +...**... +........ +........ + +char 0x31 +........ +....*... +...**... +..*.*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +....*... +..*****. +........ +........ + +char 0x32 +........ +...**... +..*..*.. +.*....*. +.*....*. +......*. +.....*.. +....*... +...*.... +..*..... +..*..... +.*...... +.*...... +.******. +........ +........ + +char 0x33 +........ +...**... +..*..*.. +.*....*. +......*. +......*. +.....*.. +...**... +.....*.. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x34 +........ +....**.. +....**.. +....**.. +...*.*.. +...*.*.. +...*.*.. +..*..*.. +..*..*.. +.*...*.. +.******. +.....*.. +.....*.. +...****. +........ +........ + +char 0x35 +........ +.*****.. +.*...... +.*...... +.*...... +.*.**... +.**..*.. +......*. +......*. +......*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x36 +........ +...**... +..*..*.. +.*....*. +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x37 +........ +.******. +.*....*. +.*....*. +.....*.. +.....*.. +....*... +....*... +....*... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x38 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x39 +........ +...**... +..*..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..**. +...**.*. +......*. +.*....*. +..*..*.. +...**... +........ +........ + +char 0x3a +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +........ +...**... +...**... +........ +........ + +char 0x3b +........ +........ +........ +........ +........ +...**... +...**... +........ +........ +........ +........ +...**... +...**... +....*... +....*... +...*.... + +char 0x3c +........ +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +........ + +char 0x3d +........ +........ +........ +........ +........ +........ +*******. +........ +........ +*******. +........ +........ +........ +........ +........ +........ + +char 0x3e +........ +*....... +.*...... +..*..... +...*.... +....*... +.....*.. +......*. +......*. +.....*.. +....*... +...*.... +..*..... +.*...... +*....... +........ + +char 0x3f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +.....*.. +....*... +...*.... +...*.... +........ +........ +...**... +...**... +........ +........ + +char 0x40 +........ +..***... +.*...*.. +*.....*. +*..**.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*.*.*.*. +*..***.. +*....... +.*...**. +..***... +........ +........ + +char 0x41 +........ +...**... +...**... +...**... +...**... +..*..*.. +..*..*.. +..*..*.. +..*..*.. +.******. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x42 +........ +****.... +.*..*... +.*...*.. +.*...*.. +.*...*.. +.*..*... +.****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +*****... +........ +........ + +char 0x43 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*....... +*....... +*....... +*.....*. +.*....*. +.*...*.. +..***... +........ +........ + +char 0x44 +........ +*****... +.*...*.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...*.. +.*...*.. +*****... +........ +........ + +char 0x45 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x46 +........ +*******. +.*....*. +.*....*. +.*...... +.*...... +.*...*.. +.*****.. +.*...*.. +.*...*.. +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x47 +........ +..***.*. +.*...**. +.*....*. +*.....*. +*....... +*....... +*..****. +*.....*. +*.....*. +*.....*. +.*....*. +.*...**. +..***... +........ +........ + +char 0x48 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.******. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x49 +........ +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x4a +........ +...***** +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +*....*.. +.*..*... +..**.... +........ + +char 0x4b +........ +***..*** +.*....*. +.*...*.. +.*..*... +.*.*.... +.*.*.... +.**..... +.*.*.... +.*.*.... +.*..*... +.*...*.. +.*....*. +***..*** +........ +........ + +char 0x4c +........ +****.... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*...... +.*....*. +.*....*. +*******. +........ +........ + +char 0x4d +........ +**....** +.*....*. +.**..**. +.**..**. +.**..**. +.*.**.*. +.*.**.*. +.*.**.*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x4e +........ +**...*** +.*....*. +.**...*. +.**...*. +.*.*..*. +.*.*..*. +.*.*..*. +.*..*.*. +.*..*.*. +.*..*.*. +.*...**. +.*...**. +***...*. +........ +........ + +char 0x4f +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x50 +........ +*****... +.*...*.. +.*....*. +.*....*. +.*....*. +.*...*.. +.****... +.*...... +.*...... +.*...... +.*...... +.*...... +****.... +........ +........ + +char 0x51 +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*..*..*. +*...*.*. +.*...*.. +..***.*. +........ +........ + +char 0x52 +........ +******.. +.*....*. +.*....*. +.*....*. +.*....*. +.*****.. +.*...*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x53 +........ +..***.*. +.*...**. +*.....*. +*.....*. +*....... +.*...... +..***... +.....*.. +......*. +*.....*. +*.....*. +**...*.. +*.***... +........ +........ + +char 0x54 +........ +*******. +*..*..*. +*..*..*. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x55 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..****.. +........ +........ + +char 0x56 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...**... +...**... +........ +........ + +char 0x57 +........ +***..*** +.*....*. +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x58 +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +..*..*.. +..*..*.. +..*..*.. +.*....*. +.*....*. +***..*** +........ +........ + +char 0x59 +........ +***.***. +.*...*.. +.*...*.. +.*...*.. +..*.*... +..*.*... +..*.*... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x5a +........ +*******. +*....*.. +*....*.. +....*... +....*... +...*.... +...*.... +..*..... +..*..... +.*...... +.*....*. +*.....*. +*******. +........ +........ + +char 0x5b +........ +..*****. +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*..... +..*****. +........ + +char 0x5c +*....... +*....... +.*...... +.*...... +..*..... +..*..... +..*..... +...*.... +...*.... +....*... +....*... +.....*.. +.....*.. +.....*.. +......*. +......*. + +char 0x5d +........ +.*****.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.*****.. +........ + +char 0x5e +........ +...*.... +..*.*... +.*...*.. +*.....*. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x5f +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +........ + +char 0x60 +...*.... +....*... +.....*.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x61 +........ +........ +........ +........ +........ +.***.... +....*... +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +*...**.. +.***.**. +........ +........ + +char 0x62 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +........ +........ + +char 0x63 +........ +........ +........ +........ +........ +..**.... +.*..**.. +*....*.. +*....*.. +*....... +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x64 +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.**. +........ +........ + +char 0x65 +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +******.. +*....... +*.....*. +.*....*. +..****.. +........ +........ + +char 0x66 +....***. +...*.... +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +.*****.. +........ +........ + +char 0x67 +........ +........ +........ +........ +........ +..**.**. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +.....*.. +.****... + +char 0x68 +**...... +.*...... +.*...... +.*...... +.*...... +.*.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x69 +........ +...*.... +...*.... +........ +........ +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6a +........ +.....*.. +.....*.. +........ +........ +....**.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +.....*.. +....*... +....*... +..**.... + +char 0x6b +**...... +.*...... +.*...... +.*...... +.*...... +.*..***. +.*...*.. +.*..*... +.*.*.... +.**..... +.*.*.... +.*..*... +.*...*.. +***..**. +........ +........ + +char 0x6c +..**.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +..***... +........ +........ + +char 0x6d +........ +........ +........ +........ +........ +****.**. +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +.*..*..* +**.**.** +........ +........ + +char 0x6e +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +***...** +........ +........ + +char 0x6f +........ +........ +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x70 +........ +........ +........ +........ +........ +**.**... +.**..*.. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.**..*.. +.*.**... +.*...... +***..... + +char 0x71 +........ +........ +........ +........ +........ +..**.*.. +.*..**.. +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +.*..**.. +..**.*.. +.....*.. +....***. + +char 0x72 +........ +........ +........ +........ +........ +**.***.. +.**...*. +.*....*. +.*...... +.*...... +.*...... +.*...... +.*...... +***..... +........ +........ + +char 0x73 +........ +........ +........ +........ +........ +.****.*. +*....**. +*.....*. +**...... +..***... +.....**. +*.....*. +**....*. +*.****.. +........ +........ + +char 0x74 +........ +........ +...*.... +...*.... +...*.... +.*****.. +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +....***. +........ +........ + +char 0x75 +........ +........ +........ +........ +........ +**...**. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*....*. +.*...**. +..***.** +........ +........ + +char 0x76 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +........ +........ + +char 0x77 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +.*.**.*. +.*.**.*. +.*.**.*. +..*..*.. +..*..*.. +..*..*.. +........ +........ + +char 0x78 +........ +........ +........ +........ +........ +**...**. +.*...*.. +..*.*... +..*.*... +...*.... +..*.*... +..*.*... +.*...*.. +**...**. +........ +........ + +char 0x79 +........ +........ +........ +........ +........ +***..*** +.*....*. +.*....*. +..*..*.. +..*..*.. +..*..*.. +...**... +...**... +...*.... +...*.... +.**..... + +char 0x7a +........ +........ +........ +........ +........ +*******. +*.....*. +*....*.. +....*... +...*.... +..*..... +.*....*. +*.....*. +*******. +........ +........ + +char 0x7b +........ +.....**. +....*... +...*.... +...*.... +...*.... +...*.... +.**..... +...*.... +...*.... +...*.... +...*.... +....*... +.....**. +........ +........ + +char 0x7c +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0x7d +........ +.**..... +...*.... +....*... +....*... +....*... +....*... +.....**. +....*... +....*... +....*... +....*... +...*.... +.**..... +........ +........ + +char 0x7e +........ +.***..*. +*...**.. +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0x7f +........ +........ +........ +........ +...*.... +..*.*... +.*...*.. +*.....*. +*******. +*.....*. +*******. +........ +........ +........ +........ +........ + +char 0x80 +........ +..***... +.*...*.. +*.....*. +*....... +*....... +*....... +*....... +*....... +*....... +*....... +*.....*. +.*...*.. +..***... +...*.... +..*..... + +char 0x81 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x82 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x83 +........ +...*.... +..*.*... +.*...*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x84 +........ +........ +..*..*.. +..*..*.. +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x85 +...*.... +....*... +.....*.. +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x86 +........ +...**... +..*..*.. +...**... +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0x87 +........ +........ +........ +........ +........ +..****.. +.*....*. +*....... +*....... +*....... +*....... +*....... +.*....*. +..****.. +....*... +...*.... + +char 0x88 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x89 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8a +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*******. +*....... +*.....*. +.*...*.. +..***... +........ +........ + +char 0x8b +........ +........ +..*..*.. +..*..*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8c +........ +...*.... +..*.*... +.*...*.. +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8d +...*.... +....*... +.....*.. +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x8e +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x8f +........ +..***... +.*...*.. +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*******. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0x90 +....**.. +....*... +...*.... +*******. +*....... +*....... +*....... +*....... +*****... +*....... +*....... +*....... +*....... +*******. +........ +........ + +char 0x91 +........ +........ +........ +........ +........ +.**..... +...***.. +...*..*. +.***..*. +*..****. +*..*.... +*..*.... +*..*..*. +.**.**.. +........ +........ + +char 0x92 +....**.. +...*.... +..*..... +..*.*... +..*.*... +..*.*... +*******. +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +..*.*... +........ +........ + +char 0x93 +........ +...*.... +..*.*... +.*...*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x94 +........ +........ +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x95 +...*.... +....*... +.....*.. +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x96 +........ +...*.... +..*.*... +.*...*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x97 +...*.... +....*... +.....*.. +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0x98 +........ +........ +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +.*...*.. +.*...*.. +..*.*... +..*.*... +...*.... +...*.... +..*..... +..*..... +.*...... + +char 0x99 +..*..*.. +..*..*.. +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9a +..*..*.. +..*..*.. +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0x9b +........ +..*.*... +..*.*... +..*.*... +..****.. +.**.*.*. +*.*.*... +*.*.*... +*.*.*... +*.*.*... +*.*.*... +.**.*.*. +..****.. +..*.*... +..*.*... +..*.*... + +char 0x9c +........ +....**.. +...*..*. +..*..... +..*..... +..*..... +******.. +..*..... +..*..... +..*..... +.**..... +*.*..... +*.**..*. +.*..**.. +........ +........ + +char 0x9d +........ +*.....*. +*.....*. +.*...*.. +..*.*... +...*.... +*******. +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0x9e +........ +***..... +*..*.... +*...*... +*...*... +*...*... +*..*.*.. +***..*.. +*..***** +*....*.. +*....*.. +*....*.. +*....*.. +*....*.. +........ +........ + +char 0x9f +........ +....**.. +...*..*. +...*.... +...*.... +...*.... +*******. +...*.... +...*.... +...*.... +...*.... +...*.... +*..*.... +.**..... +........ +........ + +char 0xa0 +....**.. +....*... +...*.... +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +........ + +char 0xa1 +....**.. +....*... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xa2 +....**.. +....*... +...*.... +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa3 +....**.. +....*... +...*.... +........ +........ +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*....*. +..*****. +........ +........ + +char 0xa4 +........ +...*..*. +..*.*.*. +..*..*.. +........ +*****... +*....*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +........ +........ + +char 0xa5 +...*..*. +..*.*.*. +..*..*.. +........ +*.....*. +**....*. +**....*. +*.*...*. +*..*..*. +*..*..*. +*...*.*. +*....**. +*....**. +*.....*. +........ +........ + +char 0xa6 +........ +........ +........ +.****... +.....*.. +.....*.. +..****.. +.*...*.. +*....*.. +*....*.. +.*...*.. +..*****. +........ +*******. +........ +........ + +char 0xa7 +........ +........ +........ +..***... +.*...*.. +*.....*. +*.....*. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +*******. +........ +........ + +char 0xa8 +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +..*..... +.*...*.. +*.....*. +*.....*. +*.....*. +.*...*.. +..***... +........ +........ + +char 0xa9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +*....... +*....... +*....... +........ +........ + +char 0xaa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +*******. +......*. +......*. +......*. +........ +........ + +char 0xab +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +.****... +.....*.. +..***... +.*...... +.*****.. +........ +........ + +char 0xac +........ +...*.... +..**.... +...*.... +...*.... +...*.... +........ +*******. +........ +...**... +..*.*... +.*..*... +.*****.. +....*... +........ +........ + +char 0xad +........ +...*.... +...*.... +........ +........ +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +........ +........ + +char 0xae +........ +........ +........ +........ +...*..*. +..*..*.. +.*..*... +*..*.... +*..*.... +.*..*... +..*..*.. +...*..*. +........ +........ +........ +........ + +char 0xaf +........ +........ +........ +........ +*..*.... +.*..*... +..*..*.. +...*..*. +...*..*. +..*..*.. +.*..*... +*..*.... +........ +........ +........ +........ + +char 0xb0 +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. +...*...* +.*...*.. + +char 0xb1 +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. +.*.*.*.* +*.*.*.*. + +char 0xb2 +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* +.***.*** +**.***.* + +char 0xb3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb6 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb7 +........ +........ +........ +........ +........ +........ +........ +******.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xb8 +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xb9 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xba +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbb +........ +........ +........ +........ +........ +........ +........ +******.. +.....*.. +****.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xbc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*.. +.....*.. +******.. +........ +........ +........ +........ +........ +........ + +char 0xbd +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******.. +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xbe +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +...*.... +****.... +........ +........ +........ +........ +........ +........ + +char 0xbf +........ +........ +........ +........ +........ +........ +........ +****.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc0 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc1 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc3 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc4 +........ +........ +........ +........ +........ +........ +........ +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xc5 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc6 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xc7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xc8 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xc9 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xca +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xcb +........ +........ +........ +........ +........ +........ +........ +******** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcc +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*** +...*.... +...*.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcd +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xce +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +........ +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xcf +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +........ +******** +........ +........ +........ +........ +........ +........ + +char 0xd0 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd1 +........ +........ +........ +........ +........ +........ +........ +******** +........ +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd2 +........ +........ +........ +........ +........ +........ +........ +******** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd3 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...***** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xd4 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...***** +...*.... +...***** +........ +........ +........ +........ +........ +........ + +char 0xd5 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd6 +........ +........ +........ +........ +........ +........ +........ +...***** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd7 +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +****.*** +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. +...*.*.. + +char 0xd8 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +******** +...*.... +******** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xd9 +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +****.... +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xda +........ +........ +........ +........ +........ +........ +........ +...***** +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... +...*.... + +char 0xdb +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdc +........ +........ +........ +........ +........ +........ +........ +........ +******** +******** +******** +******** +******** +******** +******** +******** + +char 0xdd +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... +****.... + +char 0xde +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** +....**** + +char 0xdf +******** +******** +******** +******** +******** +******** +******** +******** +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xe9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xea +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xeb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xec +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xed +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xee +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xef +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf0 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf1 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf2 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf3 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf4 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf5 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf6 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf7 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf8 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xf9 +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfa +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfb +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfc +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfd +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xfe +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ + +char 0xff +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ +........ diff --git a/30_day/haribote/haribote.sys b/30_day/haribote/haribote.sys new file mode 100644 index 0000000000000000000000000000000000000000..e098d2b2dc72ce95ff296ef38e8f320f59a0abbd GIT binary patch literal 33331 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 + +void init_pic(void) +/* PIC初始化 */ +{ + io_out8(PIC0_IMR, 0xff ); /* 禁止所有中断 */ + io_out8(PIC1_IMR, 0xff ); /* 禁止所有中断 */ + + io_out8(PIC0_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC0_ICW2, 0x20 ); /* IRQ0-7由INT20-27接收 */ + io_out8(PIC0_ICW3, 1 << 2); /* PIC1由IRQ2相连 */ + io_out8(PIC0_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC1_ICW1, 0x11 ); /* 边缘触发模式(edge trigger mode) */ + io_out8(PIC1_ICW2, 0x28 ); /* IRQ8-15由INT28-2f接收 */ + io_out8(PIC1_ICW3, 2 ); /* PIC1由IRQ2连接 */ + io_out8(PIC1_ICW4, 0x01 ); /* 无缓冲区模式 */ + + io_out8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外全部禁止 */ + io_out8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中断 */ + + return; +} diff --git a/30_day/haribote/ipl20.nas b/30_day/haribote/ipl20.nas new file mode 100644 index 0000000..9b14835 --- /dev/null +++ b/30_day/haribote/ipl20.nas @@ -0,0 +1,109 @@ +; haribote-ipl +; TAB=4 + +CYLS EQU 20 ; 声明CYLS=20 + + ORG 0x7c00 ; 指明程序装载地址 + +; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code + + JMP entry + DB 0x90 + DB "HARIBOTE" ; 启动扇区名称(8字节) + DW 512 ; 每个扇区(sector)大小(必须512字节) + DB 1 ; 簇(cluster)大小(必须为1个扇区) + DW 1 ; FAT起始位置(一般为第一个扇区) + DB 2 ; FAT个数(必须为2) + DW 224 ; 根目录大小(一般为224项) + DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512) + DB 0xf0 ; 磁盘类型(必须为0xf0) + DW 9 ; FAT的长度(必??9扇区) + DW 18 ; 一个磁道(track)有几个扇区(必须为18) + DW 2 ; 磁头数(必??2) + DD 0 ; 不使用分区,必须是0 + DD 2880 ; 重写一次磁盘大小 + DB 0,0,0x29 ; 意义不明(固定) + DD 0xffffffff ; (可能是)卷标号码 + DB "HARIBOTEOS " ; 磁盘的名称(必须为11字?,不足填空格) + DB "FAT12 " ; 磁盘格式名称(必??8字?,不足填空格) + RESB 18 ; 先空出18字节 + +; 程序主体 + +entry: + MOV AX,0 ; 初始化寄存器 + MOV SS,AX + MOV SP,0x7c00 + MOV DS,AX + +; 读取磁盘 + + MOV AX,0x0820 + MOV ES,AX + MOV CH,0 ; 柱面0 + MOV DH,0 ; 磁头0 + MOV CL,2 ; 扇区2 + +readloop: + MOV SI,0 ; 记录失败次数寄存器 + +retry: + MOV AH,0x02 ; AH=0x02 : 读入磁盘 + MOV AL,1 ; 1个扇区 + MOV BX,0 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 调用磁盘BIOS + JNC next ; 没出错则跳转到fin + ADD SI,1 ; 往SI加1 + CMP SI,5 ; 比较SI与5 + JAE error ; SI >= 5 跳转到error + MOV AH,0x00 + MOV DL,0x00 ; A驱动器 + INT 0x13 ; 重置驱动器 + JMP retry +next: + MOV AX,ES ; 把内存地址后移0x200(512/16十六进制转换) + ADD AX,0x0020 + MOV ES,AX ; ADD ES,0x020因为没有ADD ES,只能通过AX进行 + ADD CL,1 ; 往CL里面加1 + CMP CL,18 ; 比较CL与18 + JBE readloop ; CL <= 18 跳转到readloop + MOV CL,1 + ADD DH,1 + CMP DH,2 + JB readloop ; DH < 2 跳转到readloop + MOV DH,0 + ADD CH,1 + CMP CH,CYLS + JB readloop ; CH < CYLS 跳转到readloop + +; 读取完毕,跳转到haribote.sys执行! + MOV [0x0ff0],CH ; IPLがどこまで読んだのかをメモ + JMP 0xc200 + +error: + MOV SI,msg + +putloop: + MOV AL,[SI] + ADD SI,1 ; 给SI加1 + CMP AL,0 + JE fin + MOV AH,0x0e ; 显示一个文字 + MOV BX,15 ; 指定字符颜色 + INT 0x10 ; 调用显卡BIOS + JMP putloop + +fin: + HLT ; 让CPU停止,等待指令 + JMP fin ; 无限循环 + +msg: + DB 0x0a, 0x0a ; 换行两次 + DB "load error" + DB 0x0a ; 换行 + DB 0 + + RESB 0x7dfe-$ ; 填写0x00直到0x001fe + + DB 0x55, 0xaa diff --git a/30_day/haribote/jp.nas b/30_day/haribote/jp.nas new file mode 100644 index 0000000..2662459 --- /dev/null +++ b/30_day/haribote/jp.nas @@ -0,0 +1,107 @@ +; haribote-ipl +; TAB=4 + +CYLS EQU 20 ; ǂ܂œǂݍނ + + ORG 0x7c00 ; ̃vOǂɓǂݍ܂̂ + +; ȉ͕WIFAT12tH[}bgtbs[fBXN̂߂̋Lq + + JMP entry + DB 0x90 + DB "HARIBOTE" ; u[gZN^̖ORɏĂ悢i8oCgj + DW 512 ; 1ZN^̑傫i512ɂȂ΂Ȃj + DB 1 ; NX^̑傫i1ZN^ɂȂ΂Ȃj + DW 1 ; FATǂn܂邩iʂ1ZN^ڂɂj + DB 2 ; FAŤi2ɂȂ΂Ȃj + DW 224 ; [gfBNg̈̑傫iʂ224Ggɂj + DW 2880 ; ̃hCȗ傫i2880ZN^ɂȂ΂Ȃj + DB 0xf0 ; fBÃ^Cvi0xf0ɂȂ΂Ȃj + DW 9 ; FAT̈̒i9ZN^ɂȂ΂Ȃj + DW 18 ; 1gbNɂ‚̃ZN^邩i18ɂȂ΂Ȃj + DW 2 ; wbh̐i2ɂȂ΂Ȃj + DD 0 ; p[eBVgĂȂ̂ł͕K0 + DD 2880 ; ̃hCu傫x + DB 0,0,0x29 ; 悭킩Ȃǂ̒lɂĂƂ炵 + DD 0xffffffff ; Ԃ{[VAԍ + DB "HARIBOTEOS " ; fBXN̖Oi11oCgj + DB "FAT12 " ; tH[}bg̖Oi8oCgj + RESB 18 ; Ƃ肠18oCgĂ + +; vO{ + +entry: + MOV AX,0 ; WX^ + MOV SS,AX + MOV SP,0x7c00 + MOV DS,AX + +; fBXNǂ + + MOV AX,0x0820 + MOV ES,AX + MOV CH,0 ; V_0 + MOV DH,0 ; wbh0 + MOV CL,2 ; ZN^2 +readloop: + MOV SI,0 ; s񐔂𐔂郌WX^ +retry: + MOV AH,0x02 ; AH=0x02 : fBXNǂݍ + MOV AL,1 ; 1ZN^ + MOV BX,0 + MOV DL,0x00 ; AhCu + INT 0x13 ; fBXNBIOSĂяo + JNC next ; G[Ȃnext + ADD SI,1 ; SI1𑫂 + CMP SI,5 ; SI5r + JAE error ; SI >= 5 error + MOV AH,0x00 + MOV DL,0x00 ; AhCu + INT 0x13 ; hCũZbg + JMP retry +next: + MOV AX,ES ; AhX0x200i߂ + ADD AX,0x0020 + MOV ES,AX ; ADD ES,0x020 Ƃ߂Ȃ̂łĂ + ADD CL,1 ; CL1𑫂 + CMP CL,18 ; CL18r + JBE readloop ; CL <= 18 readloop + MOV CL,1 + ADD DH,1 + CMP DH,2 + JB readloop ; DH < 2 readloop + MOV DH,0 + ADD CH,1 + CMP CH,CYLS + JB readloop ; CH < CYLS readloop + +; ǂݏÎharibote.syssI + + MOV [0x0ff0],CH ; IPLǂ܂œǂ񂾂̂ + JMP 0xc200 + +error: + MOV AX,0 + MOV ES,AX + MOV SI,msg +putloop: + MOV AL,[SI] + ADD SI,1 ; SI1𑫂 + CMP AL,0 + JE fin + MOV AH,0x0e ; ꕶ\t@NV + MOV BX,15 ; J[R[h + INT 0x10 ; rfIBIOSĂяo + JMP putloop +fin: + HLT ; ܂CPU~ + JMP fin ; [v +msg: + DB 0x0a, 0x0a ; s2 + DB "load error" + DB 0x0a ; s + DB 0 + + RESB 0x7dfe-$ ; 0x7dfe܂ł0x00Ŗ߂閽 + + DB 0x55, 0xaa diff --git a/30_day/haribote/keyboard.c b/30_day/haribote/keyboard.c new file mode 100644 index 0000000..eb5140a --- /dev/null +++ b/30_day/haribote/keyboard.c @@ -0,0 +1,44 @@ +/* 键盘控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *keyfifo; +int keydata0; + +void inthandler21(int *esp) +{ + int data; + io_out8(PIC0_OCW2, 0x61); /* 把IRQ-01接收信号结束的信息通知给PIC */ + data = io_in8(PORT_KEYDAT); + fifo32_put(keyfifo, data + keydata0); + return; +} + +#define PORT_KEYSTA 0x0064 +#define KEYSTA_SEND_NOTREADY 0x02 +#define KEYCMD_WRITE_MODE 0x60 +#define KBC_MODE 0x47 + +void wait_KBC_sendready(void) +{ + /* 等待键盘控制电路准备完毕 */ + for (;;) { + if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) { + break; + } + } + return; +} + +void init_keyboard(struct FIFO32 *fifo, int data0) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + keyfifo = fifo; + keydata0 = data0; + /* 键盘控制器的初始化 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, KBC_MODE); + return; +} diff --git a/30_day/haribote/make.bat b/30_day/haribote/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/haribote/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/haribote/memory.c b/30_day/haribote/memory.c new file mode 100644 index 0000000..54a447a --- /dev/null +++ b/30_day/haribote/memory.c @@ -0,0 +1,162 @@ +/* �������֌W */ + +#include "bootpack.h" + +#define EFLAGS_AC_BIT 0x00040000 +#define CR0_CACHE_DISABLE 0x60000000 + +unsigned int memtest(unsigned int start, unsigned int end) +{ + char flg486 = 0; + unsigned int eflg, cr0, i; + + /* 确认CPU是386还是486以上的 */ + eflg = io_load_eflags(); + eflg |= EFLAGS_AC_BIT; /* AC-bit = 1 */ + io_store_eflags(eflg); + eflg = io_load_eflags(); + if ((eflg & EFLAGS_AC_BIT) != 0) { + /* 如果是386,即使设定AC=1,AC的值还会自动回到0 */ + flg486 = 1; + } + + eflg &= ~EFLAGS_AC_BIT; /* AC-bit = 0 */ + io_store_eflags(eflg); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 |= CR0_CACHE_DISABLE; /* 禁止缓存 */ + store_cr0(cr0); + } + + i = memtest_sub(start, end); + + if (flg486 != 0) { + cr0 = load_cr0(); + cr0 &= ~CR0_CACHE_DISABLE; /* 允许缓存 */ + store_cr0(cr0); + } + + return i; +} + +void memman_init(struct MEMMAN *man) +{ + man->frees = 0; /* 可用信息数目 */ + man->maxfrees = 0; /* 用于观察可用状况:frees的最大值 */ + man->lostsize = 0; /* 释放失败的内存的大小总和 */ + man->losts = 0; /* 释放失败次数 */ + return; +} + +unsigned int memman_total(struct MEMMAN *man) +/* 报告空余内存大小的合计 */ +{ + unsigned int i, t = 0; + for (i = 0; i < man->frees; i++) { + t += man->free[i].size; + } + return t; +} + +unsigned int memman_alloc(struct MEMMAN *man, unsigned int size) +/* 分配 */ +{ + unsigned int i, a; + for (i = 0; i < man->frees; i++) { + if (man->free[i].size >= size) { + /* 找到了足够大的内存 */ + a = man->free[i].addr; + man->free[i].addr += size; + man->free[i].size -= size; + if (man->free[i].size == 0) { + /* 如果free[i]变成了0,就减掉一条可用信息 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 代入结构体 */ + } + } + return a; + } + } + return 0; /* 没有可用空间 */ +} + +int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size) +/* 释放 */ +{ + int i, j; + /* 为便于归纳内存,将free[]按照addr的顺序排列 */ + /* 所以,先决定应该放在哪里 */ + for (i = 0; i < man->frees; i++) { + if (man->free[i].addr > addr) { + break; + } + } + /* free[i - 1].addr < addr < free[i].addr */ + if (i > 0) { + /* 前面有可用内存 */ + if (man->free[i - 1].addr + man->free[i - 1].size == addr) { + /* 可以与前面的可用内存归纳到一起 */ + man->free[i - 1].size += size; + if (i < man->frees) { + /* 后面也有 */ + if (addr + size == man->free[i].addr) { + /* 也可以与后面的可用内存归纳到一起 */ + man->free[i - 1].size += man->free[i].size; + /* man->free[i]删除 */ + /* free[i]变成0后归纳到前面去 */ + man->frees--; + for (; i < man->frees; i++) { + man->free[i] = man->free[i + 1]; /* 结构体赋值 */ + } + } + } + return 0; /* 成功完成 */ + } + } + /* 不能与前面的可用空间归纳到一起 */ + if (i < man->frees) { + /* 后面还有 */ + if (addr + size == man->free[i].addr) { + /* 可以与后面的内容归纳到一起 */ + man->free[i].addr = addr; + man->free[i].size += size; + return 0; /* 成功完成 */ + } + } + /* 既不能与前面归纳到一起,也不能与后面归纳到一起 */ + if (man->frees < MEMMAN_FREES) { + /* free[i]之后的,向后移动,腾出一点可用空间 */ + for (j = man->frees; j > i; j--) { + man->free[j] = man->free[j - 1]; + } + man->frees++; + if (man->maxfrees < man->frees) { + man->maxfrees = man->frees; /* 更新最大值 */ + } + man->free[i].addr = addr; + man->free[i].size = size; + return 0; /* 成功完成 */ + } + /* 不能往后移动 */ + man->losts++; + man->lostsize += size; + return -1; /* 失败 */ +} + +unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size) +{ + unsigned int a; + size = (size + 0xfff) & 0xfffff000; + a = memman_alloc(man, size); + return a; +} + +int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size) +{ + int i; + size = (size + 0xfff) & 0xfffff000; + i = memman_free(man, addr, size); + return i; +} diff --git a/30_day/haribote/mouse.c b/30_day/haribote/mouse.c new file mode 100644 index 0000000..0c6403e --- /dev/null +++ b/30_day/haribote/mouse.c @@ -0,0 +1,76 @@ +/* 鼠标控制代码 */ + +#include "bootpack.h" + +struct FIFO32 *mousefifo; +int mousedata0; + +void inthandler2c(int *esp) +/* 来自PS/2鼠标的中断 */ +{ + int data; + io_out8(PIC1_OCW2, 0x64); /* 把IRQ-12接收信号结束的信息通知给PIC1 */ + io_out8(PIC0_OCW2, 0x62); /* 把IRQ-02接收信号结束的信息通知给PIC0 */ + data = io_in8(PORT_KEYDAT); + fifo32_put(mousefifo, data + mousedata0); + return; +} + +#define KEYCMD_SENDTO_MOUSE 0xd4 +#define MOUSECMD_ENABLE 0xf4 + +void enable_mouse(struct FIFO32 *fifo, int data0, struct MOUSE_DEC *mdec) +{ + /* 将FIFO缓冲区的信息保存到全局变量里 */ + mousefifo = fifo; + mousedata0 = data0; + /* 鼠标有效 */ + wait_KBC_sendready(); + io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE); + wait_KBC_sendready(); + io_out8(PORT_KEYDAT, MOUSECMD_ENABLE); + /* 顺利的话,ACK(0xfa)会被发送*/ + mdec->phase = 0; /* 等待鼠标的0xfa的阶段*/ +return; +} + +int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat) +{ + if (mdec->phase == 0) { + /* 等待鼠标的0xfa的阶段 */ + if (dat == 0xfa) { + mdec->phase = 1; + } + return 0; + } + if (mdec->phase == 1) { + /* 等待鼠标第一字节的阶段 */ + mdec->buf[0] = dat; + mdec->phase = 2; + return 0; + } + if (mdec->phase == 2) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[1] = dat; + mdec->phase = 3; + return 0; + } + if (mdec->phase == 3) { + /* 等待鼠标第二字节的阶段 */ + mdec->buf[2] = dat; + mdec->phase = 1; + mdec->btn = mdec->buf[0] & 0x07; + mdec->x = mdec->buf[1]; + mdec->y = mdec->buf[2]; + if ((mdec->buf[0] & 0x10) != 0) { + mdec->x |= 0xffffff00; + } + if ((mdec->buf[0] & 0x20) != 0) { + mdec->y |= 0xffffff00; + } + mdec->y = - mdec->y; /* 鼠标的y方向与画面符号相反 */ + return 1; + } + /* 应该不可能到这里来 */ + return -1; +} diff --git a/30_day/haribote/mtask.c b/30_day/haribote/mtask.c new file mode 100644 index 0000000..f67b935 --- /dev/null +++ b/30_day/haribote/mtask.c @@ -0,0 +1,203 @@ +/* 多任务管理 */ + +#include "bootpack.h" + +struct TASKCTL *taskctl; +struct TIMER *task_timer; + +struct TASK *task_now(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + return tl->tasks[tl->now]; +} + +void task_add(struct TASK *task) +{ + struct TASKLEVEL *tl = &taskctl->level[task->level]; + tl->tasks[tl->running] = task; + tl->running++; + task->flags = 2; /*活动中*/ + return; +} + +void task_remove(struct TASK *task) +{ + int i; + struct TASKLEVEL *tl = &taskctl->level[task->level]; + + /*寻找task所在的位置*/ + for (i = 0; i < tl->running; i++) { + if (tl->tasks[i] == task) { + /*在这里 */ + break; + } + } + + tl->running--; + if (i < tl->now) { + tl->now--; /*需要移动成员,要相应地处理 */ + } + if (tl->now >= tl->running) { + /*如果now的值出现异常,则进行修正*/ + tl->now = 0; + } + task->flags = 1; /* 休眠中 */ + + /* 移动 */ + for (; i < tl->running; i++) { + tl->tasks[i] = tl->tasks[i + 1]; + } + return; +} + +void task_switchsub(void) +{ + int i; + /*寻找最上层的LEVEL */ + for (i = 0; i < MAX_TASKLEVELS; i++) { + if (taskctl->level[i].running > 0) { + break; /*找到了*/ + } + } + taskctl->now_lv = i; + taskctl->lv_change = 0; + return; +} + +void task_idle(void) +{ + for (;;) { + io_hlt(); + } +} + +struct TASK *task_init(struct MEMMAN *memman) +{ + int i; + struct TASK *task, *idle; + struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + + + taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL)); + for (i = 0; i < MAX_TASKS; i++) { + taskctl->tasks0[i].flags = 0; + taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8; + taskctl->tasks0[i].tss.ldtr = (TASK_GDT0 + MAX_TASKS + i) * 8; + set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32); + set_segmdesc(gdt + TASK_GDT0 + MAX_TASKS + i, 15, (int) taskctl->tasks0[i].ldt, AR_LDT); + } + for (i = 0; i < MAX_TASKLEVELS; i++) { + taskctl->level[i].running = 0; + taskctl->level[i].now = 0; + } + + task = task_alloc(); + task->flags = 2; /*活动中标志*/ + task->priority = 2; /* 0.02秒*/ + task->level = 0; /*最高LEVEL */ + task_add(task); + task_switchsub(); /* LEVEL 设置*/ + load_tr(task->sel); + task_timer = timer_alloc(); + timer_settime(task_timer, task->priority); + + idle = task_alloc(); + idle->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024; + idle->tss.eip = (int) &task_idle; + idle->tss.es = 1 * 8; + idle->tss.cs = 2 * 8; + idle->tss.ss = 1 * 8; + idle->tss.ds = 1 * 8; + idle->tss.fs = 1 * 8; + idle->tss.gs = 1 * 8; + task_run(idle, MAX_TASKLEVELS - 1, 1); + + return task; +} + +struct TASK *task_alloc(void) +{ + int i; + struct TASK *task; + for (i = 0; i < MAX_TASKS; i++) { + if (taskctl->tasks0[i].flags == 0) { + task = &taskctl->tasks0[i]; + task->flags = 1; /*正在使用的标志*/ + task->tss.eflags = 0x00000202; /* IF = 1; */ + task->tss.eax = 0; /*这里先置为0*/ + task->tss.ecx = 0; + task->tss.edx = 0; + task->tss.ebx = 0; + task->tss.ebp = 0; + task->tss.esi = 0; + task->tss.edi = 0; + task->tss.es = 0; + task->tss.ds = 0; + task->tss.fs = 0; + task->tss.gs = 0; + task->tss.iomap = 0x40000000; + task->tss.ss0 = 0; + return task; + } + } + return 0; /*全部正在使用*/ +} + +void task_run(struct TASK *task, int level, int priority) +{ + if (level < 0) { + level = task->level; /*不改变LEVEL */ + } + if (priority > 0) { + task->priority = priority; + } + if (task->flags == 2 && task->level != level) { + /*改变活动中的LEVEL */ + task_remove(task); /*这里执行之后flag的值会变为1,于是下面的if语句块也会被执行*/ + } + if (task->flags != 2) { + /*从休眠状态唤醒的情形*/ + task->level = level; + task_add(task); + } + taskctl->lv_change = 1; /*下次任务切换时检查LEVEL */ + return; +} + +void task_sleep(struct TASK *task) +{ + struct TASK *now_task; + if (task->flags == 2) { + /*如果处于活动状态*/ + now_task = task_now(); + task_remove(task); /*执行此语句的话flags将变为1 */ + if (task == now_task) { + /*如果是让自己休眠,则需要进行任务切换*/ + task_switchsub(); + now_task = task_now(); /*在设定后获取当前任务的值*/ + farjmp(0, now_task->sel); + } + } + return; +} + + +void task_switch(void) +{ + struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; + struct TASK *new_task, *now_task = tl->tasks[tl->now]; + tl->now++; + if (tl->now == tl->running) { + tl->now = 0; + } + if (taskctl->lv_change != 0) { + task_switchsub(); + tl = &taskctl->level[taskctl->now_lv]; + } + new_task = tl->tasks[tl->now]; + timer_settime(task_timer, new_task->priority); + if (new_task != now_task) { + farjmp(0, new_task->sel); + } + return; +} diff --git a/30_day/haribote/naskfunc.nas b/30_day/haribote/naskfunc.nas new file mode 100644 index 0000000..a45775d --- /dev/null +++ b/30_day/haribote/naskfunc.nas @@ -0,0 +1,291 @@ +; naskfunc +; TAB=4 + +[FORMAT "WCOFF"] ; 制作目标文件的模式 +[INSTRSET "i486p"] ; 使用到486为止的指令 +[BITS 32] ; 3制作32位模式用的机器语言 +[FILE "naskfunc.nas"] ; 文件名 + + GLOBAL _io_hlt, _io_cli, _io_sti, _io_stihlt + GLOBAL _io_in8, _io_in16, _io_in32 + GLOBAL _io_out8, _io_out16, _io_out32 + GLOBAL _io_load_eflags, _io_store_eflags + GLOBAL _load_gdtr, _load_idtr + GLOBAL _load_cr0, _store_cr0 + GLOBAL _load_tr + GLOBAL _asm_inthandler20, _asm_inthandler21 + GLOBAL _asm_inthandler2c, _asm_inthandler0c + GLOBAL _asm_inthandler0d, _asm_end_app + GLOBAL _memtest_sub + GLOBAL _farjmp, _farcall + GLOBAL _asm_hrb_api, _start_app + EXTERN _inthandler20, _inthandler21 + EXTERN _inthandler2c, _inthandler0d + EXTERN _inthandler0c + EXTERN _hrb_api + +[SECTION .text] + +_io_hlt: ; void io_hlt(void); + HLT + RET + +_io_cli: ; void io_cli(void); + CLI + RET + +_io_sti: ; void io_sti(void); + STI + RET + +_io_stihlt: ; void io_stihlt(void); + STI + HLT + RET + +_io_in8: ; int io_in8(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AL,DX + RET + +_io_in16: ; int io_in16(int port); + MOV EDX,[ESP+4] ; port + MOV EAX,0 + IN AX,DX + RET + +_io_in32: ; int io_in32(int port); + MOV EDX,[ESP+4] ; port + IN EAX,DX + RET + +_io_out8: ; void io_out8(int port, int data); + MOV EDX,[ESP+4] ; port + MOV AL,[ESP+8] ; data + OUT DX,AL + RET + +_io_out16: ; void io_out16(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,AX + RET + +_io_out32: ; void io_out32(int port, int data); + MOV EDX,[ESP+4] ; port + MOV EAX,[ESP+8] ; data + OUT DX,EAX + RET + +_io_load_eflags: ; int io_load_eflags(void); + PUSHFD ; PUSH EFLAGS + POP EAX + RET + +_io_store_eflags: ; void io_store_eflags(int eflags); + MOV EAX,[ESP+4] + PUSH EAX + POPFD ; POP EFLAGS + RET + +_load_gdtr: ; void load_gdtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LGDT [ESP+6] + RET + +_load_idtr: ; void load_idtr(int limit, int addr); + MOV AX,[ESP+4] ; limit + MOV [ESP+6],AX + LIDT [ESP+6] + RET + +_load_cr0: ; int load_cr0(void); + MOV EAX,CR0 + RET + +_store_cr0: ; void store_cr0(int cr0); + MOV EAX,[ESP+4] + MOV CR0,EAX + RET + +_load_tr: ; void load_tr(int tr); + LTR [ESP+4] ; tr + RET + +_asm_inthandler20: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler20 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler21: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler21 + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler2c: + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler2c + POP EAX + POPAD + POP DS + POP ES + IRETD + +_asm_inthandler0c: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0c + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; 在INT 0x0c中也需要这句 + IRETD + +_asm_inthandler0d: + STI + PUSH ES + PUSH DS + PUSHAD + MOV EAX,ESP + PUSH EAX + MOV AX,SS + MOV DS,AX + MOV ES,AX + CALL _inthandler0d + CMP EAX,0 + JNE _asm_end_app + POP EAX + POPAD + POP DS + POP ES + ADD ESP,4 ; INT 0x0d需要这句 + IRETD + +_memtest_sub: ; unsigned int memtest_sub(unsigned int start, unsigned int end) + PUSH EDI ; (由于还要使用EBX, ESI, EDI) + PUSH ESI + PUSH EBX + MOV ESI,0xaa55aa55 ; pat0 = 0xaa55aa55; + MOV EDI,0x55aa55aa ; pat1 = 0x55aa55aa; + MOV EAX,[ESP+12+4] ; i = start; +mts_loop: + MOV EBX,EAX + ADD EBX,0xffc ; p = i + 0xffc; + MOV EDX,[EBX] ; old = *p; + MOV [EBX],ESI ; *p = pat0; + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP EDI,[EBX] ; if (*p != pat1) goto fin; + JNE mts_fin + XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff; + CMP ESI,[EBX] ; if (*p != pat0) goto fin; + JNE mts_fin + MOV [EBX],EDX ; *p = old; + ADD EAX,0x1000 ; i += 0x1000; + CMP EAX,[ESP+12+8] ; if (i <= end) goto mts_loop; + JBE mts_loop + POP EBX + POP ESI + POP EDI + RET +mts_fin: + MOV [EBX],EDX ; *p = old; + POP EBX + POP ESI + POP EDI + RET + +_farjmp: ; void farjmp(int eip, int cs); + JMP FAR [ESP+4] ; eip, cs + RET + +_farcall: ; void farcall(int eip, int cs); + CALL FAR [ESP+4] ; eip, cs + RET + +_asm_hrb_api: + STI + PUSH DS + PUSH ES + PUSHAD ; 用于保存的PUSH + PUSHAD ; 用于向hrb_api传值的PUSH + MOV AX,SS + MOV DS,AX ; 将操作系统用段地址存入DS和ES + MOV ES,AX + CALL _hrb_api + CMP EAX,0 ; 当EAX不为0时程序结束 + JNE _asm_end_app + ADD ESP,32 + POPAD + POP ES + POP DS + IRETD +_asm_end_app: +; EAX为tss.esp0的地址 + MOV ESP,[EAX] + MOV DWORD [EAX+4],0 + POPAD + RET ; 返回cmd_app + +_start_app: ; void start_app(int eip, int cs, int esp, int ds, int *tss_esp0); + PUSHAD ; 将32位寄存器的值全部保存起来 + MOV EAX,[ESP+36] ; 应用程序用EIP + MOV ECX,[ESP+40] ; 应用程序用CS + MOV EDX,[ESP+44] ; 应用程序用ESP + MOV EBX,[ESP+48] ; 应用程序用DS/SS + MOV EBP,[ESP+52] ; tss.esp0的地址 + MOV [EBP ],ESP ; 保存操作系统用ESP + MOV [EBP+4],SS ; 保存操作系统用SS + MOV ES,BX + MOV DS,BX + MOV FS,BX + MOV GS,BX +; 下面调整栈,以免用RETF跳转到应用程序 + OR ECX,3 ; 将应用程序用段号和3进行OR运算 + OR EBX,3 ; 将应用程序用段号和3进行OR运算 + PUSH EBX ; 应用程序的SS + PUSH EDX ; 应用程序的ESP + PUSH ECX ; 应用程序的CS + PUSH EAX ; 应用程序的EIP + RETF +; 应用程序结束后不会回到这里 diff --git a/30_day/haribote/sheet.c b/30_day/haribote/sheet.c new file mode 100644 index 0000000..14aa0ea --- /dev/null +++ b/30_day/haribote/sheet.c @@ -0,0 +1,294 @@ +/* sheet */ + +#include "bootpack.h" + +#define SHEET_USE 1 + +struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize) +{ + struct SHTCTL *ctl; + int i; + ctl = (struct SHTCTL *) memman_alloc_4k(memman, sizeof (struct SHTCTL)); + if (ctl == 0) { + goto err; + } + ctl->map = (unsigned char *) memman_alloc_4k(memman, xsize * ysize); + if (ctl->map == 0) { + memman_free_4k(memman, (int) ctl, sizeof (struct SHTCTL)); + goto err; + } + ctl->vram = vram; + ctl->xsize = xsize; + ctl->ysize = ysize; + ctl->top = -1; /* 没有一张SHEET */ + for (i = 0; i < MAX_SHEETS; i++) { + ctl->sheets0[i].flags = 0; /* 标记为未使用 */ + ctl->sheets0[i].ctl = ctl; /* 记录所属*/ + } +err: + return ctl; +} + +struct SHEET *sheet_alloc(struct SHTCTL *ctl) +{ + struct SHEET *sht; + int i; + for (i = 0; i < MAX_SHEETS; i++) { + if (ctl->sheets0[i].flags == 0) { + sht = &ctl->sheets0[i]; + sht->flags = SHEET_USE; /* 标记为正在使用*/ + sht->height = -1; /* 隐藏 */ + sht->task = 0; /*不使用自动关闭功能*/ + return sht; + } + } + return 0; /* 所有的SHEET都处于正在使用状态*/ +} + +void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv) +{ + sht->buf = buf; + sht->bxsize = xsize; + sht->bysize = ysize; + sht->col_inv = col_inv; + return; +} + +void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1, sid4, *p;; + unsigned char *buf, sid, *map = ctl->map; + struct SHEET *sht; + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= ctl->top; h++) { + sht = ctl->sheets[h]; + sid = sht - ctl->sheets0; /* 将进行了减法计算的地址作为图层号码使用 */ + buf = sht->buf; + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } + if (by1 > sht->bysize) { by1 = sht->bysize; } + if (sht->col_inv == -1) { + if ((sht->vx0 & 3) == 0 && (bx0 & 3) == 0 && (bx1 & 3) == 0) { + /*无透明色图层专用的高速版(4字节型)*/ + bx1 = (bx1 - bx0) / 4; /* MOV次数*/ + sid4 = sid | sid << 8 | sid << 16 | sid << 24; + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + vx = sht->vx0 + bx0; + p = (int *) &map[vy * ctl->xsize + vx]; + for (bx = 0; bx < bx1; bx++) { + p[bx] = sid4; + } + } + } else { + /*无透明色图层专用的高速版(1字节型)*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + map[vy * ctl->xsize + vx] = sid; + } + } + } + } else { + /*有透明色图层用的普通版*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (buf[by * sht->bxsize + bx] != sht->col_inv) { + map[vy * ctl->xsize + vx] = sid; + } + } + } + } + } + return; +} + +void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0, int h1) +{ + int h, bx, by, vx, vy, bx0, by0, bx1, by1, bx2, sid4, i, i1, *p, *q, *r; + unsigned char *buf, *vram = ctl->vram, *map = ctl->map, sid; + struct SHEET *sht; + + /* 如果refresh的范围超出了画面则修正 */ + if (vx0 < 0) { vx0 = 0; } + if (vy0 < 0) { vy0 = 0; } + if (vx1 > ctl->xsize) { vx1 = ctl->xsize; } + if (vy1 > ctl->ysize) { vy1 = ctl->ysize; } + for (h = h0; h <= h1; h++) { + sht = ctl->sheets[h]; + buf = sht->buf; + sid = sht - ctl->sheets0; + + /* 使用vx0~vy1,对bx0~by1进行倒推 */ + bx0 = vx0 - sht->vx0; + by0 = vy0 - sht->vy0; + bx1 = vx1 - sht->vx0; + by1 = vy1 - sht->vy0; + if (bx0 < 0) { bx0 = 0; } /* 处理刷新范围在图层外侧 */ + if (by0 < 0) { by0 = 0; } + if (bx1 > sht->bxsize) { bx1 = sht->bxsize; } /* 应对不同的重叠方式 */ + if (by1 > sht->bysize) { by1 = sht->bysize; } + if ((sht->vx0 & 3) == 0) { + /* 4字节型*/ + i = (bx0 + 3) / 4; /* bx0除以4(小数进位)*/ + i1 = bx1 / 4; /* bx1除以4(小数舍去)*/ + i1 = i1 - i; + sid4 = sid | sid << 8 | sid << 16 | sid << 24; + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1 && (bx & 3) != 0; bx++) { + /*前面被4除多余的部分逐个字节写入*/ + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + vx = sht->vx0 + bx; + p = (int *) &map[vy * ctl->xsize + vx]; + q = (int *) &vram[vy * ctl->xsize + vx]; + r = (int *) &buf[by * sht->bxsize + bx]; + for (i = 0; i < i1; i++) { + /* 4的倍数部分*/ + if (p[i] == sid4) { + q[i] = r[i]; /*估计大多数会是这种情况,因此速度会变快*/ + } else { + bx2 = bx + i * 4; + vx = sht->vx0 + bx2; + if (map[vy * ctl->xsize + vx + 0] == sid) { + vram[vy * ctl->xsize + vx + 0] = buf[by * sht->bxsize + bx2 + 0]; + } + if (map[vy * ctl->xsize + vx + 1] == sid) { + vram[vy * ctl->xsize + vx + 1] = buf[by * sht->bxsize + bx2 + 1]; + } + if (map[vy * ctl->xsize + vx + 2] == sid) { + vram[vy * ctl->xsize + vx + 2] = buf[by * sht->bxsize + bx2 + 2]; + } + if (map[vy * ctl->xsize + vx + 3] == sid) { + vram[vy * ctl->xsize + vx + 3] = buf[by * sht->bxsize + bx2 + 3]; + } + } + } + for (bx += i1 * 4; bx < bx1; bx++) { + /*后面被4除多余的部分逐个字节写入*/ + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + } + } else { + /* 1字节型*/ + for (by = by0; by < by1; by++) { + vy = sht->vy0 + by; + for (bx = bx0; bx < bx1; bx++) { + vx = sht->vx0 + bx; + if (map[vy * ctl->xsize + vx] == sid) { + vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx]; + } + } + } + } + } + return; +} + +void sheet_updown(struct SHEET *sht, int height) +{ + struct SHTCTL *ctl = sht->ctl; + int h, old = sht->height; /* 存储设置前的高度信息 */ + if (height > ctl->top + 1) { + height = ctl->top + 1; + } + if (height < -1) { + height = -1; + } + sht->height = height;/* 设定高度 */ + + /* 下面主要是进行sheets[]的重新排列 */ + if (old > height) { /* 比以前低 */ + if (height >= 0) { + /* 把中间的往上提 */ + for (h = old; h > height; h--) { + ctl->sheets[h] = ctl->sheets[h - 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1, old); + } else { /* 隐藏 */ + if (ctl->top > old) { + /* 把上面的降下来 */ + for (h = old; h < ctl->top; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + } + ctl->top--; /* 由于显示中的图层减少了一个,所以最上面的图层高度下降 */ + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0, old - 1); + } + } else if (old < height) { /* 比以前高 */ + if (old >= 0) { + /* 把中间的拉下去 */ + for (h = old; h < height; h++) { + ctl->sheets[h] = ctl->sheets[h + 1]; + ctl->sheets[h]->height = h; + } + ctl->sheets[height] = sht; + } else { /* 由隐藏状态转为显示状态 */ + /* 将已在上面的提上来 */ + for (h = ctl->top; h >= height; h--) { + ctl->sheets[h + 1] = ctl->sheets[h]; + ctl->sheets[h + 1]->height = h + 1; + } + ctl->sheets[height] = sht; + ctl->top++; /* 由于已显示的图层增加了1个,所以最上面的图层高度增加 */ + } + sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height); + sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height, height); /* 按新图层信息重新绘制画面 */ + } + return; +} + +void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1) +{ + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面*/ + sheet_refreshsub(sht->ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1, sht->height, sht->height); + } + return; +} + +void sheet_slide(struct SHEET *sht, int vx0, int vy0) +{ + struct SHTCTL *ctl = sht->ctl; + int old_vx0 = sht->vx0, old_vy0 = sht->vy0; + sht->vx0 = vx0; + sht->vy0 = vy0; + if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面 */ + sheet_refreshmap(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0); + sheet_refreshmap(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height); + sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0, sht->height - 1); + sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height, sht->height); + } + return; +} + +void sheet_free(struct SHEET *sht) +{ + if (sht->height >= 0) { + sheet_updown(sht, -1); /* 如果处于显示状态,则先设定为隐藏 */ + } + sht->flags = 0; /* "未使用"标志 */ + return; +} diff --git a/30_day/haribote/tek.c b/30_day/haribote/tek.c new file mode 100644 index 0000000..4062dcc --- /dev/null +++ b/30_day/haribote/tek.c @@ -0,0 +1,646 @@ +#include "bootpack.h" +#include +#include +#define NULL 0 + +typedef unsigned char UCHAR; +typedef unsigned int UINT32; +typedef UINT32 tek_TPRB; + +static int tek_decode1(int siz, UCHAR *p, UCHAR *q); +static int tek_decode2(int siz, UCHAR *p, UCHAR *q); +static int tek_decode5(int siz, UCHAR *p, UCHAR *q); + +static unsigned int tek_getnum_s7s(UCHAR **pp) +{ + unsigned int s = 0; + UCHAR *p = *pp; + do { + s = s << 7 | *p++; + } while ((s & 1) == 0); + s >>= 1; + *pp = p; + return s; +} + +int tek_getsize(unsigned char *p) +{ + static char header[15] = { + 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x41, 0x53, 0x4b, 0x43, 0x4d, 0x50 + }; + int size = -1; + if (memcmp(p + 1, header, 15) == 0 && (*p == 0x83 || *p == 0x85 || *p == 0x89)) { + p += 16; + size = tek_getnum_s7s(&p); + } + return size; +} /* (注)memcmp和strncmp差不多,这个函数忽略字符串中的0并一直比较到指定的15个字符为止*/ + +int tek_decomp(unsigned char *p, char *q, int size) +{ + int err = -1; + if (*p == 0x83) { + err = tek_decode1(size, p, q); + } else if (*p == 0x85) { + err = tek_decode2(size, p, q); + } else if (*p == 0x89) { + err = tek_decode5(size, p, q); + } + if (err != 0) { + return -1; /*失败*/ + } + return 0; /*成功*/ +} + +static int tek_lzrestore_stk1(int srcsiz, UCHAR *src, int outsiz, UCHAR *q) +{ + int by, lz, cp, ds; + UCHAR *q1 = q + outsiz, *s7ptr = src, *q0 = q; + do { + if ((by = (lz = *s7ptr++) & 0x0f) == 0) + by = tek_getnum_s7s(&s7ptr); + if ((lz >>= 4) == 0) + lz = tek_getnum_s7s(&s7ptr); + do { + *q++ = *s7ptr++; + } while (--by); + if (q >= q1) + break; + do { + ds = (cp = *s7ptr++) & 0x0f; + if ((ds & 1) == 0) { + do { + ds = ds << 7 | *s7ptr++; + } while ((ds & 1) == 0); + } + ds = ~(ds >> 1); + if ((cp >>= 4) == 0) { + do { + cp = cp << 7 | *s7ptr++; + } while ((cp & 1) == 0); + cp >>= 1; + } + cp++; + if (q + ds < q0) + goto err; + if (q + cp > q1) + cp = q1 - q; + do { + *q = *(q + ds); + q++; + } while (--cp); + } while (--lz); + } while (q < q1); + return 0; +err: + return 1; +} + +static int tek_decode1(int siz, UCHAR *p, UCHAR *q) +{ + int dsiz, hed, bsiz; + UCHAR *p1 = p + siz; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (dsiz > bsiz || (hed & 0x21) != 0x01) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + if (tek_getnum_s7s(&p) != 0) + return 1; + return tek_lzrestore_stk1(p1 - p, p, dsiz, q); + } + return 0; +} + +static unsigned int tek_getnum_s7(UCHAR **pp) +{ + unsigned int s = 0, b = 0, a = 1; + UCHAR *p = *pp; + for (;;) { + s = s << 7 | *p++; + if (s & 1) + break; + a <<= 7; + b += a; + } + s >>= 1; + *pp = p; + return s + b; +} + +static int tek_lzrestore_stk2(int srcsiz, UCHAR *src, int outsiz, UCHAR *q) +{ + int cp, ds, repdis[4], i, j; + UCHAR *q1 = q + outsiz, *s7ptr = src, *q0 = q, bylz, cbylz; + for (j = 0; j < 4; j++) + repdis[j] = -1 - j; + bylz = cbylz = 0; + if (outsiz) { + if (tek_getnum_s7s(&s7ptr)) + return 1; + do { + j = 0; + do { + j++; + if (j >= 17) { + j += tek_getnum_s7s(&s7ptr); + break; + } + if (cbylz == 0) { + cbylz = 8; + bylz = *s7ptr++; + } + cbylz--; + i = bylz & 1; + bylz >>= 1; + } while (i == 0); + do { + *q++ = *s7ptr++; + } while (--j); + if (q >= q1) + break; + + j = 0; + do { + j++; + if (j >= 17) { + j += tek_getnum_s7s(&s7ptr); + break; + } + if (cbylz == 0) { + cbylz = 8; + bylz = *s7ptr++; + } + cbylz--; + i = bylz & 1; + bylz >>= 1; + } while (i == 0); + do { + i = *s7ptr++; + cp = i >> 4; + i &= 0x0f; + if ((i & 1) == 0) + i |= (tek_getnum_s7(&s7ptr) + 1) << 4; + i >>= 1; + ds = ~(i - 6); + if (i < 4) + ds = repdis[i]; + if (i == 4) + ds = repdis[0] - tek_getnum_s7(&s7ptr) - 1; + if (i == 5) + ds = repdis[0] + tek_getnum_s7(&s7ptr) + 1; + if (cp == 0) + cp = tek_getnum_s7(&s7ptr) + 16; + cp++; + if (i > 0) { + if (i > 1) { + if (i > 2) + repdis[3] = repdis[2]; + repdis[2] = repdis[1]; + } + repdis[1] = repdis[0]; + repdis[0] = ds; + } + if (q + ds < q0) + goto err; + if (q + cp > q1) + cp = q1 - q; + do { + *q = *(q + ds); + q++; + } while (--cp); + } while (--j); + } while (q < q1); + } + return 0; +err: + return 1; +} + +static int tek_decode2(int siz, UCHAR *p, UCHAR *q) +{ + UCHAR *p1 = p + siz; + int dsiz, hed, bsiz, st = 0; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (dsiz > bsiz || (hed & 0x21) != 0x01) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + st = tek_lzrestore_stk2(p1 - p, p, dsiz, q); + } + return st; +} + +static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int pb, int lp, int flags); + +static int tek_lzrestore_tek5(int srcsiz, UCHAR *src, int outsiz, UCHAR *outbuf) +{ + int wrksiz, lc, lp, pb, flags, *work, prop0, fl; + + if ((fl = (prop0 = *src) & 0x0f) == 0x01) /* 0001 */ + flags |= -1; + else if (fl == 0x05) + flags = -2; + else if (fl == 0x09) + flags &= 0; + else + return 1; + src++; + prop0 >>= 4; + if (prop0 == 0) + prop0 = *src++; + else { + static UCHAR prop0_table[] = { 0x5d, 0x00 }, prop1_table[] = { 0x00 }; + if (flags == -1) { + if (prop0 >= 3) + return 1; + prop0 = prop0_table[prop0 - 1]; + } else { + if (prop0 >= 2) + return 1; + prop0 = prop1_table[prop0 - 1]; + } + } + lp = prop0 / (9 * 5); + prop0 %= 9 * 5; + pb = prop0 / 9; + lc = prop0 % 9; + if (flags == 0) /* tek5:z2 */ + flags = *src++; + if (flags == -1) { /* stk5 */ + wrksiz = lp; + lp = pb; + pb = wrksiz; + } + wrksiz = 0x180 * sizeof (UINT32) + (0x840 + (0x300 << (lc + lp))) * sizeof (tek_TPRB); /* Å’á15KB, lc+lp=3‚È‚çA36KB */ + work = (int *) memman_alloc_4k((struct MEMMAN *) MEMMAN_ADDR, wrksiz); + if (work == NULL) + return -1; + flags = tek_decmain5(work, src, outsiz, outbuf, lc, pb, lp, flags); + memman_free_4k((struct MEMMAN *) MEMMAN_ADDR, (int) work, wrksiz); + return flags; +} + +struct tek_STR_BITMODEL { + UCHAR t, m, s, dmy; + UINT32 prb0, prb1, tmsk, ntm, lt, lt0, dmy4; +}; + +struct tek_STR_PRB { + struct tek_STR_PRB_PB { + struct tek_STR_PRB_PBST { + tek_TPRB mch, rep0l1; + } st[12]; + tek_TPRB lenlow[2][8], lenmid[2][8]; + } pb[16]; + struct tek_STR_PRB_ST { + tek_TPRB rep, repg0, repg1, repg2; + } st[12]; + tek_TPRB lensel[2][2], lenhigh[2][256], pslot[4][64], algn[64]; + tek_TPRB spdis[2][2+4+8+16+32], lenext[2+4+8+16+32]; + tek_TPRB repg3, fchgprm[2 * 32], tbmt[16], tbmm[16], fchglt; + tek_TPRB lit[1]; +}; + +struct tek_STR_RNGDEC { + UCHAR *p; + UINT32 range, code, rmsk; + jmp_buf errjmp; + struct tek_STR_BITMODEL bm[32], *ptbm[16]; + struct tek_STR_PRB probs; +}; + +static void tek_setbm5(struct tek_STR_BITMODEL *bm, int t, int m) +{ + bm->t = t; + bm->m = m; + bm->prb1 = -1 << (m + t); + bm->prb0 = ~bm->prb1; + bm->prb1 |= 1 << t; + bm->tmsk = (-1 << t) & 0xffff; + bm->prb0 &= bm->tmsk; + bm->prb1 &= bm->tmsk; + bm->ntm = ~bm->tmsk; + return; +} + +static int tek_rdget0(struct tek_STR_RNGDEC *rd, int n, int i) +{ + do { + while (rd->range < (UINT32) (1 << 24)) { + rd->range <<= 8; + rd->code = rd->code << 8 | *rd->p++; + } + rd->range >>= 1; + i += i; + if (rd->code >= rd->range) { + rd->code -= rd->range; + i |= 1; + } + } while (--n); + return ~i; +} + +static int tek_rdget1(struct tek_STR_RNGDEC *rd, tek_TPRB *prob0, int n, int j, struct tek_STR_BITMODEL *bm) +{ + UINT32 p, i, *prob, nm = n >> 4; + n &= 0x0f; + prob0 -= j; + do { + p = *(prob = prob0 + j); + if (bm->lt > 0) { + if (--bm->lt == 0) { + if (tek_rdget1(rd, &rd->probs.fchglt, 0x71, 0, &rd->bm[3]) == 0) { +err: + longjmp(rd->errjmp, 1); + } + i = bm - rd->bm; + if ((bm->s = tek_rdget1(rd, &rd->probs.fchgprm[i * 2 + bm->s], 0x71, 0, &rd->bm[1])) == 0) { + i = tek_rdget1(rd, rd->probs.tbmt, 0x74, 1, &rd->bm[2]) & 15; + if (i == 15) + goto err; + tek_setbm5(bm, i, ((tek_rdget1(rd, rd->probs.tbmm, 0x74, 1, &rd->bm[2]) - 1) & 15) + 1); + } + bm->lt = bm->lt0; + } + if (p < bm->prb0) { + p = bm->prb0; + goto fixprob; + } + if (p > bm->prb1) { + p = bm->prb1; + goto fixprob; + } + if (p & bm->ntm) { + p &= bm->tmsk; + fixprob: + *prob = p; + } + } + + while (rd->range < (UINT32) (1 << 24)) { + rd->range <<= 8; + rd->code = rd->code << 8 | *rd->p++; + } + j += j; + i = ((unsigned long long) (rd->range & rd->rmsk) * p) >> 16; + if (rd->code < i) { + j |= 1; + rd->range = i; + *prob += ((0x10000 - p) >> bm->m) & bm->tmsk; + } else { + rd->range -= i; + rd->code -= i; + *prob -= (p >> bm->m) & bm->tmsk; + } + --n; + if ((n & nm) == 0) + bm++; + } while (n); + return j; +} + +static UINT32 tek_revbit(UINT32 data, int len) +{ + UINT32 rev = 0; + do { + rev += rev + (data & 1); + data >>= 1; + } while (--len); + return rev; +} + +static int tek_getlen5(struct tek_STR_RNGDEC *rd, int m, int s_pos, int stk) +{ + int i; + if (tek_rdget1(rd, &rd->probs.lensel[m][0], 0x71, 0, rd->ptbm[3]) ^ stk) /* low */ + i = tek_rdget1(rd, rd->probs.pb[s_pos].lenlow[m], 0x73, 1, rd->ptbm[4]) & 7; + else if (tek_rdget1(rd, &rd->probs.lensel[m][1], 0x71, 0, rd->ptbm[3]) ^ stk) /* mid */ + i = tek_rdget1(rd, rd->probs.pb[s_pos].lenmid[m], 0x73, 1, rd->ptbm[5]); + else { + /* high */ + i = tek_rdget1(rd, rd->probs.lenhigh[m], 0x78, 1, rd->ptbm[6]) - (256 + 256 - 8); + if (i > 0) { + if (i < 6 && stk == 0) + i = tek_rdget1(rd, &rd->probs.lenext[(1 << i) - 2], i | 0x70, 1, rd->ptbm[7]) - 1; + else + i = tek_rdget0(rd, i, ~1) - 1; + i = tek_rdget0(rd, i, ~1) - 1; + } + i += 256 - 8 + 16; + } + return i; +} + +static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int pb, int lp, int flags) +{ + static int state_table[] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 }; + int i, j, k, pmch, rep[4], s, pos, m_pos = (1 << pb) - 1, m_lp = (1 << lp) - 1; + int stk = (flags == -1), lcr = 8 - lc, s_pos, lit0cntmsk = 0x78; + UINT32 *lit1; + struct tek_STR_RNGDEC *rd = (struct tek_STR_RNGDEC *) work; + struct tek_STR_PRB *prb = &rd->probs; + + rd->p = &src[4]; + rd->range |= -1; + rd->code = src[0] << 24 | src[1] << 16 | src[2] << 8 | src[3]; + for (i = 0; i < 4; i++) + rep[i] = ~i; + if (setjmp(rd->errjmp)) + goto err; + for (i = sizeof (struct tek_STR_PRB) / sizeof (tek_TPRB) + (0x300 << (lc + lp)) - 2; i >= 0; i--) + ((tek_TPRB *) prb)[i] = 1 << 15; + for (i = 0; i < 32; i++) { + rd->bm[i].lt = (i >= 4); + rd->bm[i].lt0 = (i < 24) ? 16 * 1024 : 8 * 1024; + rd->bm[i].s &= 0; + rd->bm[i].t = rd->bm[i].m = 5; + } + lit1 = prb->lit + ((256 << (lc + lp)) - 2); + if (stk) { + rd->rmsk = -1 << 11; + for (i = 0; i < 32; i++) + rd->bm[i].lt = 0; + for (i = 0; i < 14; i++) + rd->ptbm[i] = &rd->bm[0]; + } else { + UCHAR pt[14]; + static UCHAR pt1[14] = { + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 18, 18, 18, 8 + }; + static UCHAR pt2[14] = { + 8, 8, 10, 11, 12, 12, 14, 15, + 16, 16, 18, 18, 20, 21 + }; + /* + 0- 7:mch, mch, lit1, lensel, lenlow, lenmid, lenhigh, lenext + 8-15:pslot, pslot, sdis, sdis, align, rep-repg2 + */ + rd->rmsk |= -1; + rd->bm[1].t = 5; rd->bm[1].m = 3; /* for fchgprm */ + rd->bm[2].t = 9; rd->bm[2].m = 2; /* for tbmt, tbmm */ + if (flags & 0x40) { /* lt-flag */ + rd->bm[3].t = 0; rd->bm[3].m = 1; + prb->fchglt = 0xffff; + } + rd->bm[22].t = 0; rd->bm[22].m = 1; + prb->repg3 = 0xffff; + if (flags == -2) { /* z1 */ + rd->bm[22].lt = 0; + for (i = 0; i < 14; i++) + pt[i] = pt1[i]; + } else { + for (i = 0; i < 14; i++) + pt[i] = pt2[i]; + lit0cntmsk = (7 >> (flags & 3)) << 4 | 8; + pt[ 1] = 8 + ((flags & 0x04) != 0); /* mch */ + pt[ 5] = 12 + ((flags & 0x08) != 0); /* llm */ + pt[ 9] = 16 + ((flags & 0x10) != 0); /* pst */ + pt[11] = 18 + ((flags & 0x20) != 0); /* sds */ + } + for (i = 0; i < 14; i++) + rd->ptbm[i] = &rd->bm[pt[i]]; + } + for (i = 0; i < 32; i++) + tek_setbm5(&rd->bm[i], rd->bm[i].t, rd->bm[i].m); + + if ((tek_rdget1(rd, &prb->pb[0].st[0].mch, 0x71, 0, rd->ptbm[0]) ^ stk) == 0) + goto err; + *q++ = tek_rdget1(rd, prb->lit, lit0cntmsk, 1, &rd->bm[24]) & 0xff; + pmch &= 0; s &= 0; pos = 1; + while (pos < osiz) { + s_pos = pos & m_pos; + if (tek_rdget1(rd, &prb->pb[s_pos].st[s].mch, 0x71, 0, rd->ptbm[s > 0]) ^ stk) { + i = (q[-1] >> lcr | (pos & m_lp) << lc) << 8; + s = state_table[s]; + if (pmch == 0) + *q = tek_rdget1(rd, &prb->lit[i], lit0cntmsk, 1, &rd->bm[24]) & 0xff; + else { + struct tek_STR_BITMODEL *bm = &rd->bm[24]; + j = 1; + k = 8; + pmch = q[rep[0]]; + do { + j += j + tek_rdget1(rd, &lit1[(i + j) << 1 | pmch >> 7], 0x71, 0, rd->ptbm[2]); + k--; + if ((k & (lit0cntmsk >> 4)) == 0) + bm++; + if ((((pmch >> 7) ^ j) & 1) != 0 && k != 0) { + j = tek_rdget1(rd, &prb->lit[i + j - 1], k | (lit0cntmsk & 0x70), j, bm); + break; + } + pmch <<= 1; + } while (k); + *q = j & 0xff; + pmch &= 0; + } + pos++; + q++; + } else { /* lz */ + pmch |= 1; + if (tek_rdget1(rd, &prb->st[s].rep, 0x71, 0, rd->ptbm[13]) ^ stk) { /* len/dis */ + rep[3] = rep[2]; + rep[2] = rep[1]; + rep[1] = rep[0]; + j = i = tek_getlen5(rd, 0, s_pos, stk); + s = s < 7 ? 7 : 10; + if (j >= 4) + j = 3; + rep[0] = j = tek_rdget1(rd, prb->pslot[j], 0x76, 1, rd->ptbm[8 + (j == 3)]) & 0x3f; + if (j >= 4) { + k = (j >> 1) - 1; /* k = [1, 30] */ + rep[0] = (2 | (j & 1)) << k; + if (j < 14) /* k < 6 */ + rep[0] |= tek_revbit(tek_rdget1(rd, &prb->spdis[j & 1][(1 << k) - 2], k | 0x70, 1, rd->ptbm[10 + (k >= 4)]), k); + else { + if (stk == 0) { + if (k -= 6) + rep[0] |= tek_rdget0(rd, k, ~0) << 6; + rep[0] |= tek_revbit(tek_rdget1(rd, prb->algn, 0x76, 1, rd->ptbm[12]), 6); + } else { + rep[0] |= tek_rdget0(rd, k - 4, ~0) << 4; + rep[0] |= tek_revbit(tek_rdget1(rd, prb->algn, 0x74, 1, rd->ptbm[12]), 4); + } + } + } + rep[0] = ~rep[0]; + } else { /* repeat-dis */ + if (tek_rdget1(rd, &prb->st[s].repg0, 0x71, 0, rd->ptbm[13]) ^ stk) { /* rep0 */ + i |= -1; + if (tek_rdget1(rd, &prb->pb[s_pos].st[s].rep0l1, 0x71, 0, rd->ptbm[13]) == 0) { + s = s < 7 ? 9 : 11; + goto skip; + } + } else { + if (tek_rdget1(rd, &prb->st[s].repg1, 0x71, 0, rd->ptbm[13]) ^ stk) /* rep1 */ + i = rep[1]; + else { + if (tek_rdget1(rd, &prb->st[s].repg2, 0x71, 0, rd->ptbm[13]) ^ stk) /* rep2 */ + i = rep[2]; + else { + if (stk == 0) { + if (tek_rdget1(rd, &prb->repg3, 0x71, 0, &rd->bm[22]) == 0) + goto err; + } + i = rep[3]; /* rep3 */ + rep[3] = rep[2]; + } + rep[2] = rep[1]; + } + rep[1] = rep[0]; + rep[0] = i; + } + i = tek_getlen5(rd, 1, s_pos, stk); + s = s < 7 ? 8 : 11; + } +skip: + i += 2; + if (pos + rep[0] < 0) + goto err; + if (pos + i > osiz) + i = osiz - pos; + pos += i; + do { + *q = q[rep[0]]; + q++; + } while (--i); + } + } + return 0; +err: + return 1; +} + +static int tek_decode5(int siz, UCHAR *p, UCHAR *q) +{ + UCHAR *p1 = p + siz; + int dsiz, hed, bsiz, st = 0; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + if ((hed & 1) == 0) + st = tek_lzrestore_tek5(p1 - p + 1, p - 1, dsiz, q); + else { + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (hed & 0x20) + return 1; + if (bsiz == 256) + st = tek_lzrestore_tek5(p1 - p, p, dsiz, q); + else { + if (dsiz > bsiz) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + st = tek_lzrestore_tek5(p1 - p, p, dsiz, q); + } + } + } + return st; +} diff --git a/30_day/haribote/timer.c b/30_day/haribote/timer.c new file mode 100644 index 0000000..9018ac8 --- /dev/null +++ b/30_day/haribote/timer.c @@ -0,0 +1,169 @@ +/* 定时器 */ + +#include "bootpack.h" + +#define PIT_CTRL 0x0043 +#define PIT_CNT0 0x0040 + +struct TIMERCTL timerctl; + +#define TIMER_FLAGS_ALLOC 1 /* 已配置状态 */ +#define TIMER_FLAGS_USING 2 /* 定时器运行中 */ + +void init_pit(void) +{ + int i; + struct TIMER *t; + io_out8(PIT_CTRL, 0x34); + io_out8(PIT_CNT0, 0x9c); + io_out8(PIT_CNT0, 0x2e); + timerctl.count = 0; + for (i = 0; i < MAX_TIMER; i++) { + timerctl.timers0[i].flags = 0; /* 没有使用 */ + } + t = timer_alloc(); /* 取得一个 */ + t->timeout = 0xffffffff; + t->flags = TIMER_FLAGS_USING; + t->next = 0; /* 末尾 */ + timerctl.t0 = t; /* 因为现在只有哨兵,所以他就在最前面*/ + timerctl.next = 0xffffffff; /* 因为只有哨兵,所以下一个超时时刻就是哨兵的时刻 */ + return; +} + +struct TIMER *timer_alloc(void) +{ + int i; + for (i = 0; i < MAX_TIMER; i++) { + if (timerctl.timers0[i].flags == 0) { + timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; + timerctl.timers0[i].flags2 = 0; + return &timerctl.timers0[i]; + } + } + return 0; /* 没找到 */ +} + +void timer_free(struct TIMER *timer) +{ + timer->flags = 0; /* 未使用 */ + return; +} + +void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data) +{ + timer->fifo = fifo; + timer->data = data; + return; +} + +void timer_settime(struct TIMER *timer, unsigned int timeout) +{ + int e; + struct TIMER *t, *s; + timer->timeout = timeout + timerctl.count; + timer->flags = TIMER_FLAGS_USING; + e = io_load_eflags(); + io_cli(); + t = timerctl.t0; + if (timer->timeout <= t->timeout) { + /* 插入最前面的情况 */ + timerctl.t0 = timer; + timer->next = t; /* 下面是设定t */ + timerctl.next = timer->timeout; + io_store_eflags(e); + return; + } + for (;;) { + s = t; + t = t->next; + if (timer->timeout <= t->timeout) { + /* 插入s和t之间的情况 */ + s->next = timer; /* s下一个是timer */ + timer->next = t; /* timer的下一个是t */ + io_store_eflags(e); + return; + } + } +} + +void inthandler20(int *esp) +{ + struct TIMER *timer; + char ts = 0; + io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00接收信号结束的信息通知给PIC */ + timerctl.count++; + if (timerctl.next > timerctl.count) { + return; + } + timer = timerctl.t0; /* 首先把最前面的地址赋给timer */ + for (;;) { + /* 因为timers的定时器都处于运行状态,所以不确认flags */ + if (timer->timeout > timerctl.count) { + break; + } + /* 超时 */ + timer->flags = TIMER_FLAGS_ALLOC; + if (timer != task_timer) { + fifo32_put(timer->fifo, timer->data); + } else { + ts = 1; /* mt_timer超时*/ + } + timer = timer->next; /* 将下一个定时器的地址赋给timer*/ + } + timerctl.t0 = timer; + timerctl.next = timer->timeout; + if (ts != 0) { + task_switch(); + } + return; +} + +int timer_cancel(struct TIMER *timer) +{ + int e; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + if (timer->flags == TIMER_FLAGS_USING) { /*是否需要取消?*/ + if (timer == timerctl.t0) { + /*第一个定时器的取消处理*/ + t = timer->next; + timerctl.t0 = t; + timerctl.next = t->timeout; + } else { + /*非第一个定时器的取消处理*/ + /*找到timer前一个定时器*/ + t = timerctl.t0; + for (;;) { + if (t->next == timer) { + break; + } + t = t->next; + } + t->next = timer->next; + /*将之前“timer的下一个”指向“timer的下一个”*/ + } + timer->flags = TIMER_FLAGS_ALLOC; + io_store_eflags(e); + return 1; /*取消处理成功*/ + } + io_store_eflags(e); + return 0; /*不需要取消处理*/ +} + +void timer_cancelall(struct FIFO32 *fifo) +{ + int e, i; + struct TIMER *t; + e = io_load_eflags(); + io_cli(); /*在设置过程中禁止改变定时器状态*/ + for (i = 0; i < MAX_TIMER; i++) { + t = &timerctl.timers0[i]; + if (t->flags != 0 && t->flags2 != 0 && t->fifo == fifo) { + timer_cancel(t); + timer_free(t); + } + } + io_store_eflags(e); + return; +} diff --git a/30_day/haribote/window.c b/30_day/haribote/window.c new file mode 100644 index 0000000..df9165c --- /dev/null +++ b/30_day/haribote/window.c @@ -0,0 +1,124 @@ +/* 窗口相关函数 */ + +#include "bootpack.h" + +void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act) +{ + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, xsize - 1, 0 ); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, xsize - 2, 1 ); + boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, 0, ysize - 1); + boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, 1, ysize - 2); + boxfill8(buf, xsize, COL8_848484, xsize - 2, 1, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, xsize - 1, 0, xsize - 1, ysize - 1); + boxfill8(buf, xsize, COL8_C6C6C6, 2, 2, xsize - 3, ysize - 3); + boxfill8(buf, xsize, COL8_848484, 1, ysize - 2, xsize - 2, ysize - 2); + boxfill8(buf, xsize, COL8_000000, 0, ysize - 1, xsize - 1, ysize - 1); + make_wtitle8(buf, xsize, title, act); + return; +} + +void make_wtitle8(unsigned char *buf, int xsize, char *title, char act) +{ + static char closebtn[14][16] = { + "OOOOOOOOOOOOOOO@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQQQ@@QQQQQ$@", + "OQQQQQ@@@@QQQQ$@", + "OQQQQ@@QQ@@QQQ$@", + "OQQQ@@QQQQ@@QQ$@", + "OQQQQQQQQQQQQQ$@", + "OQQQQQQQQQQQQQ$@", + "O$$$$$$$$$$$$$$@", + "@@@@@@@@@@@@@@@@" + }; + int x, y; + char c, tc, tbc; + if (act != 0) { + tc = COL8_FFFFFF; + tbc = COL8_000084; + } else { + tc = COL8_C6C6C6; + tbc = COL8_848484; + } + boxfill8(buf, xsize, tbc, 3, 3, xsize - 4, 20); + putfonts8_asc(buf, xsize, 24, 4, tc, title); + for (y = 0; y < 14; y++) { + for (x = 0; x < 16; x++) { + c = closebtn[y][x]; + if (c == '@') { + c = COL8_000000; + } else if (c == '$') { + c = COL8_848484; + } else if (c == 'Q') { + c = COL8_C6C6C6; + } else { + c = COL8_FFFFFF; + } + buf[(5 + y) * xsize + (xsize - 21 + x)] = c; + } + } + return; +} + +void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l) +{ + struct TASK *task = task_now(); + boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15); + if (task->langmode != 0 && task->langbyte1 != 0) { + putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); + sheet_refresh(sht, x - 8, y, x + l * 8, y + 16); + } else { + putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); + sheet_refresh(sht, x, y, x + l * 8, y + 16); + } + return; +} + +void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c) +{ + int x1 = x0 + sx, y1 = y0 + sy; + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3); + boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2); + boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1); + boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1); + boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0); + return; +} + +void change_wtitle8(struct SHEET *sht, char act) +{ + int x, y, xsize = sht->bxsize; + char c, tc_new, tbc_new, tc_old, tbc_old, *buf = sht->buf; + if (act != 0) { + tc_new = COL8_FFFFFF; + tbc_new = COL8_000084; + tc_old = COL8_C6C6C6; + tbc_old = COL8_848484; + } else { + tc_new = COL8_C6C6C6; + tbc_new = COL8_848484; + tc_old = COL8_FFFFFF; + tbc_old = COL8_000084; + } + for (y = 3; y <= 20; y++) { + for (x = 3; x <= xsize - 4; x++) { + c = buf[y * xsize + x]; + if (c == tc_old && x <= xsize - 22) { + c = tc_new; + } else if (c == tbc_old) { + c = tbc_new; + } + buf[y * xsize + x] = c; + } + } + sheet_refresh(sht, 3, 3, xsize, 21); + return; +} diff --git a/30_day/hello3/!cons_9x.bat b/30_day/hello3/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/hello3/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/hello3/!cons_nt.bat b/30_day/hello3/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/hello3/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/hello3/Makefile b/30_day/hello3/Makefile new file mode 100644 index 0000000..436f686 --- /dev/null +++ b/30_day/hello3/Makefile @@ -0,0 +1,5 @@ +APP = hello3 +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/hello3/hello3.c b/30_day/hello3/hello3.c new file mode 100644 index 0000000..f71cedf --- /dev/null +++ b/30_day/hello3/hello3.c @@ -0,0 +1,11 @@ +#include "apilib.h" + +void HariMain(void) +{ + api_putchar('h'); + api_putchar('e'); + api_putchar('l'); + api_putchar('l'); + api_putchar('o'); + api_end(); +} diff --git a/30_day/hello3/make.bat b/30_day/hello3/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/hello3/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/hello4/!cons_9x.bat b/30_day/hello4/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/hello4/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/hello4/!cons_nt.bat b/30_day/hello4/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/hello4/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/hello4/Makefile b/30_day/hello4/Makefile new file mode 100644 index 0000000..ade47c9 --- /dev/null +++ b/30_day/hello4/Makefile @@ -0,0 +1,8 @@ +APP = hello4 +STACK = 1k +MALLOC = 0k + +include ../app_make.txt + +$(STDAPP).hrb : $(APP).org Makefile + $(COPY) $(APP).org $(APP).hrb diff --git a/30_day/hello4/hello4.c b/30_day/hello4/hello4.c new file mode 100644 index 0000000..5a69068 --- /dev/null +++ b/30_day/hello4/hello4.c @@ -0,0 +1,7 @@ +#include "stdlib.h" + +void HariMain(void) +{ + printf("hello, world : %s %d\n", "aaa", 10); + exit(0); +} diff --git a/30_day/hello4/make.bat b/30_day/hello4/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/hello4/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/hello5/!cons_9x.bat b/30_day/hello5/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/hello5/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/hello5/!cons_nt.bat b/30_day/hello5/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/hello5/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/hello5/Makefile b/30_day/hello5/Makefile new file mode 100644 index 0000000..e07f802 --- /dev/null +++ b/30_day/hello5/Makefile @@ -0,0 +1,8 @@ +APP = hello5 +STACK = 1k +MALLOC = 0k + +include ../app_make.txt + +$(APP).hrb : $(APP).org Makefile + $(COPY) $(APP).org $(APP).hrb diff --git a/30_day/hello5/hello5.nas b/30_day/hello5/hello5.nas new file mode 100644 index 0000000..ee62330 --- /dev/null +++ b/30_day/hello5/hello5.nas @@ -0,0 +1,20 @@ +[FORMAT "WCOFF"] +[INSTRSET "i486p"] +[BITS 32] +[FILE "hello5.nas"] + + GLOBAL _HariMain + +[SECTION .text] + +_HariMain: + MOV EDX,2 + MOV EBX,msg + INT 0x40 + MOV EDX,4 + INT 0x40 + +[SECTION .data] + +msg: + DB "hello, world", 0x0a, 0 diff --git a/30_day/hello5/make.bat b/30_day/hello5/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/hello5/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/invader/!cons_9x.bat b/30_day/invader/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/invader/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/invader/!cons_nt.bat b/30_day/invader/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/invader/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/invader/Makefile b/30_day/invader/Makefile new file mode 100644 index 0000000..a60ffdb --- /dev/null +++ b/30_day/invader/Makefile @@ -0,0 +1,5 @@ +APP = invader +STACK = 90k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/invader/invader.c b/30_day/invader/invader.c new file mode 100644 index 0000000..d26d3b1 --- /dev/null +++ b/30_day/invader/invader.c @@ -0,0 +1,281 @@ +#include /* sprintf */ +#include /* strlen */ +#include "apilib.h" + +void putstr(int win, char *winbuf, int x, int y, int col, unsigned char *s); +void wait(int i, int timer, char *keyflag); + +static unsigned char charset[16 * 8] = { + + /* invader(0) */ + 0x00, 0x00, 0x00, 0x43, 0x5f, 0x5f, 0x5f, 0x7f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x20, 0x3f, 0x00, + + /* invader(1) */ + 0x00, 0x0f, 0x7f, 0xff, 0xcf, 0xcf, 0xcf, 0xff, + 0xff, 0xe0, 0xff, 0xff, 0xc0, 0xc0, 0xc0, 0x00, + + /* invader(2) */ + 0x00, 0xf0, 0xfe, 0xff, 0xf3, 0xf3, 0xf3, 0xff, + 0xff, 0x07, 0xff, 0xff, 0x03, 0x03, 0x03, 0x00, + + /* invader(3) */ + 0x00, 0x00, 0x00, 0xc2, 0xfa, 0xfa, 0xfa, 0xfe, + 0xf8, 0xf8, 0xf8, 0xf8, 0x00, 0x04, 0xfc, 0x00, + + /* fighter(0) */ + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x43, 0x47, 0x4f, 0x5f, 0x7f, 0x7f, 0x00, + + /* fighter(1) */ + 0x18, 0x7e, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, + 0xff, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0x00, + + /* fighter(2) */ + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0xc2, 0xe2, 0xf2, 0xfa, 0xfe, 0xfe, 0x00, + + /* laser */ + 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00 +}; +/* invader:"abcd", fighter:"efg", laser:"h" */ + +void HariMain(void) +{ + /* + fx:自机的x坐标(fighter_x) + lx,ly:等离子炮弹的坐标(laser_x,laser_y) + ix,iy:外星人群的坐标(invaders_x,in-vaders_y) + idir:外星人群的移动方向(invaders_direc-tion) + laserwait:等离子炮弹的剩余充电时间 + movewait:当这个变量变为0时外星人群前进一步 + movewait0:movewait的初始值(消灭30只敌人后减少) + invline:外星人群的行数(invaders_line) + score:当前得分 + high:最高得分 + point:得分的增加量(奖金的单价?) + invstr:将外星人群的状态显示为字符串的变量 + */ + + int win, timer, i, j, fx, laserwait, lx = 0, ly; + int ix, iy, movewait0, movewait, idir; + int invline, score, high, point; + char winbuf[336 * 261], invstr[32 * 6], s[12], keyflag[4], *p; + static char invstr0[32] = " abcd abcd abcd abcd abcd "; + + win = api_openwin(winbuf, 336, 261, -1, "invader"); + api_boxfilwin(win, 6, 27, 329, 254, 0); + timer = api_alloctimer(); + api_inittimer(timer, 128); + + high = 0; + putstr(win, winbuf, 22, 0, 7, "HIGH:00000000"); + +restart: + score = 0; + point = 1; + putstr(win, winbuf, 4, 0, 7, "SCORE:00000000"); + movewait0 = 20; + fx = 18; + putstr(win, winbuf, fx, 13, 6, "efg"); + wait(100, timer, keyflag); + +next_group: + wait(100, timer, keyflag); + ix = 7; + iy = 1; + invline = 6; + for (i = 0; i < 6; i++) { + for (j = 0; j < 27; j++) { + invstr[i * 32 + j] = invstr0[j]; + } + putstr(win, winbuf, ix, iy + i, 2, invstr + i * 32); + } + keyflag[0] = 0; + keyflag[1] = 0; + keyflag[2] = 0; + + ly = 0; /*不显示*/ + laserwait = 0; + movewait = movewait0; + idir = +1; + wait(100, timer, keyflag); + + for (;;) { + if (laserwait != 0) { + laserwait--; + keyflag[2 /* space */] = 0; + } + + wait(4, timer, keyflag); + + /*自机的处理*/ + if (keyflag[0 /* left */] != 0 && fx > 0) { + fx--; + putstr(win, winbuf, fx, 13, 6, "efg "); + keyflag[0 /* left */] = 0; + } + if (keyflag[1 /* right */] != 0 && fx < 37) { + putstr(win, winbuf, fx, 13, 6, " efg"); + fx++; + keyflag[1 /* right */] = 0; + } + if (keyflag[2 /* space */] != 0 && laserwait == 0) { + laserwait = 15; + lx = fx + 1; + ly = 13; + } + + /*外星人移动*/ + if (movewait != 0) { + movewait--; + } else { + movewait = movewait0; + if (ix + idir > 14 || ix + idir < 0) { + if (iy + invline == 13) { + break; /* GAME OVER */ + } + idir = - idir; + putstr(win, winbuf, ix + 1, iy, 0, " "); + iy++; + } else { + ix += idir; + } + for (i = 0; i < invline; i++) { + putstr(win, winbuf, ix, iy + i, 2, invstr + i * 32); + } + } + + /*炮弹处理*/ + if (ly > 0) { + if (ly < 13) { + if (ix < lx && lx < ix + 25 && iy <= ly && ly < iy + invline) { + putstr(win, winbuf, ix, ly, 2, invstr + (ly - iy) * 32); + } else { + putstr(win, winbuf, lx, ly, 0, " "); + } + } + ly--; + if (ly > 0) { + putstr(win, winbuf, lx, ly, 3, "h"); + } else { + point -= 10; + if (point <= 0) { + point = 1; + } + } + if (ix < lx && lx < ix + 25 && iy <= ly && ly < iy + invline) { + p = invstr + (ly - iy) * 32 + (lx - ix); + if (*p != ' ') { + /* hit ! */ + score += point; + point++; + sprintf(s, "%08d", score); + putstr(win, winbuf, 10, 0, 7, s); + if (high < score) { + high = score; + putstr(win, winbuf, 27, 0, 7, s); + } + for (p--; *p != ' '; p--) { } + for (i = 1; i < 5; i++) { + p[i] = ' '; + } + putstr(win, winbuf, ix, ly, 2, invstr + (ly - iy) * 32); + for (; invline > 0; invline--) { + for (p = invstr + (invline - 1) * 32; *p != 0; p++) { + if (*p != ' ') { + goto alive; + } + } + } + /*全部消灭*/ + movewait0 -= movewait0 / 3; + goto next_group; + alive: + ly = 0; + } + } + } + } + + /* GAME OVER */ + putstr(win, winbuf, 15, 6, 1, "GAME OVER"); + wait(0, timer, keyflag); + for (i = 1; i < 14; i++) { + putstr(win, winbuf, 0, i, 0, " "); + } + goto restart; +} + +void putstr(int win, char *winbuf, int x, int y, int col, unsigned char *s) +{ + int c, x0, i; + char *p, *q, t[2]; + x = x * 8 + 8; + y = y * 16 + 29; + x0 = x; + i = strlen(s); /*计算s的字符数*/ + api_boxfilwin(win + 1, x, y, x + i * 8 - 1, y + 15, 0); + q = winbuf + y * 336; + t[1] = 0; + for (;;) { + c = *s; + if (c == 0) { + break; + } + if (c != ' ') { + if ('a' <= c && c <= 'h') { + p = charset + 16 * (c - 'a'); + q += x; + for (i = 0; i < 16; i++) { + if ((p[i] & 0x80) != 0) { q[0] = col; } + if ((p[i] & 0x40) != 0) { q[1] = col; } + if ((p[i] & 0x20) != 0) { q[2] = col; } + if ((p[i] & 0x10) != 0) { q[3] = col; } + if ((p[i] & 0x08) != 0) { q[4] = col; } + if ((p[i] & 0x04) != 0) { q[5] = col; } + if ((p[i] & 0x02) != 0) { q[6] = col; } + if ((p[i] & 0x01) != 0) { q[7] = col; } + q += 336; + } + q -= 336 * 16 + x; + } else { + t[0] = *s; + api_putstrwin(win + 1, x, y, col, 1, t); + } + } + s++; + x += 8; + } + api_refreshwin(win, x0, y, x, y + 16); + return; +} + +void wait(int i, int timer, char *keyflag) +{ + int j; + if (i > 0) { + /*等待一段时间*/ + api_settimer(timer, i); + i = 128; + } else { + i = 0x0a; /* Enter */ + } + for (;;) { + j = api_getkey(1); + if (i == j) { + break; + } + if (j == '4') { + keyflag[0 /* left */] = 1; + } + if (j == '6') { + keyflag[1 /* right */] = 1; + } + if (j == ' ') { + keyflag[2 /* space */] = 1; + } + } + return; +} diff --git a/30_day/invader/make.bat b/30_day/invader/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/invader/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/iroha/!cons_9x.bat b/30_day/iroha/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/iroha/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/iroha/!cons_nt.bat b/30_day/iroha/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/iroha/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/iroha/Makefile b/30_day/iroha/Makefile new file mode 100644 index 0000000..df134ad --- /dev/null +++ b/30_day/iroha/Makefile @@ -0,0 +1,5 @@ +APP = iroha +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/iroha/iroha.c b/30_day/iroha/iroha.c new file mode 100644 index 0000000..3ed1dd8 --- /dev/null +++ b/30_day/iroha/iroha.c @@ -0,0 +1,9 @@ +#include "apilib.h" + +void HariMain(void) +{ + static char s[9] = { 0xb2, 0xdb, 0xca, 0xc6, 0xce, 0xcd, 0xc4, 0x0a, 0x00 }; + /*半角片假名イロハニホヘト的字符编码+换行+0 */ + api_putstr0(s); + api_end(); +} diff --git a/30_day/iroha/make.bat b/30_day/iroha/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/iroha/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/lines/!cons_9x.bat b/30_day/lines/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/lines/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/lines/!cons_nt.bat b/30_day/lines/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/lines/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/lines/Makefile b/30_day/lines/Makefile new file mode 100644 index 0000000..45a6aad --- /dev/null +++ b/30_day/lines/Makefile @@ -0,0 +1,5 @@ +APP = lines +STACK = 1k +MALLOC = 48k + +include ../app_make.txt diff --git a/30_day/lines/lines.c b/30_day/lines/lines.c new file mode 100644 index 0000000..5217faa --- /dev/null +++ b/30_day/lines/lines.c @@ -0,0 +1,22 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win, i; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "lines"); + for (i = 0; i < 8; i++) { + api_linewin(win + 1, 8, 26, 77, i * 9 + 26, i); + api_linewin(win + 1, 88, 26, i * 9 + 88, 89, i); + } + api_refreshwin(win, 6, 26, 154, 90); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_closewin(win); + api_end(); +} diff --git a/30_day/lines/make.bat b/30_day/lines/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/lines/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/make.bat b/30_day/make.bat new file mode 100644 index 0000000..e489766 --- /dev/null +++ b/30_day/make.bat @@ -0,0 +1 @@ +..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/nihongo/jpn16v00.bin b/30_day/nihongo/jpn16v00.bin new file mode 100644 index 0000000000000000000000000000000000000000..135f07ce88e6ddefe60f5b6768ac36b52ac3fe76 GIT binary patch literal 311296 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 Uf>;Y0Qnog1f# zT`~I}@jb;%gy>zVzmdh`#$V!u-}mo+U`#lb@L&(r2Ldx#L9HQ!_(r_1U*QqZBg-Gh zxkCzjsTSm?D>DKYNP9cwa0+IoCeUa`QScqvA9#_wbBV*8byJDG}0{l zPpupe45abPX(TfW$IC;ZF(?rloiL$Osf%@%G?bJ=gnNuk_@~ z<&y@_0H`9&Af%$NM9&p}XabzcZ%94>zc8?3`o#74gHr%lKrf4T-@Es&hY5gc(9es- z+5MX@X8wmuZyFnwkMGkERKXuRLu~fK+VC~}Uy`qyjY&Wy-TK5YSDgS|MZTt_3fci3 z*4u=AhWTG3O2|dQLGoeCb^W;29?r%a#k@!`pUd;OMX1gv_ z>lVKS`5o)bOrWZP5`!V}6>$W6`^c}}*C!{x4*96W2a#uPW*jT}?>fpu+v3EJ$2-2l zL$M#v&0WI4u=<&2_%U}$@!)UC6NwCiC(am<={;g0MzioWH4FsV-ywq{QAGqKT zUJ!i5Q`s`9rMz8yWUPeE|On;l)evP2@9k(87Z5$3aUI=HYy(hjzZ6xZ>ht$38zX zI%?>bVE!^&!FL+?2X@GXwdDzYU?=$v;5GzG3|7Oyf9@5w5vPrPUG-b8yB34~wieXi zwot5PLz~5yy5}=|_k5e*w)Ryfej$JH+<|O^LVzD(!jizAb@(X0+=2oLchDVRKu3qt zXh3Z0Gzvy?_ouAD1M91}qoqO}2afzV%Fa1LGQh+Uu{Fsv1aLU~*XK~*K*PpYp7puR zry5^$`+K^Fq0dL)0N&&z5+^Pxq=n5}~*VRp1!>g`oqBU z+K9IjtgaiLM`k@7QZ%l69ul&hKWXXgJf+WA?7L(f(yB?{;5_h&9 zVt#NR|H2lyXz5*&keHzFLs#$;fFO!*WC0<6LZUSE+4YNuEz9ThOEMRM)cBB(9En1~ zP=3%-=9=&92k+^6-GUF1 zCMVlF2y^Q|zpTgKY5z(2zjhU}@=u`jZcy~XO+kEimC)Cf>+cORgN)#l_x>>O?N>@@ z1`YcXbEt^^!C`DZa9uLQ;r#jr{}=w6cr_;Tp7BquY_Pa>Js$zh`X~j&QMQ z%Z#<~hvDcZJ%6S+G0$h6|4RIw{J{470Vg60KGQ#bK3Y@7vCQk}2kyEnAtb__>UF8u_X5o_C5Kh{Ee;6rELl~4&tZC8yovsi26Eu%Re0p6}Kgt)~+E5 z3;qavK%L{dUcW&9m|mMQ1TpV|uHMoJyd5lEN+0^uE+2S?x6{O;6d%XL(9q(>qWBJE zWfA`k=*ZFJ__-{a{$v^Vm zISA!>`BD=E(jkEKSL7o__*j4s@R2W>?uC7rm+#SS8oMG8lH{L96F&J3+n$W|_6(P! zYrM5rPEFKV-+|J3^B*#)b%@2_2a`%M4u>H;-N1wYPA8`KO_%mfn;7Dm(ekIoACDLB z`tc#^hq$ogY&RCTY_{}S)=#SwU=R2cjSgmddtst@=`+Q%y%Dp3bFiCzH!Jra{pTNl_%8V8`mUipvDlGV zZ*PaaSicYS!(_xE!<$#bA>rV(%eKQH zGA?B^D}Tv|EHqL8gz)kAO8zQ*zkWq9E^`-!)R9~J?K_3-miz&k?#L~h5!Tt2%r zM}%|drPC^)^hZ1nVk{9Z4t|EhKqvo#xzJqv5Wq9GGl7e4qn|6A{YJ8b_x;n~$IgcQ zAo1J1NnnA)I^y|wAFaJRJ-}8x&_Vo00Wx9%cI~iL;zZHauvB~<^ed}(aM=1h+ctnU^*Ke`A1mc0z zXU4PSPg`&qd*oxEg8U>}2vJq^{m@;=1C$rYylT7uYJBVK+@JVL)-I<6kMY%>_gZvN z$*ZrP%Dg)NMdW3S%6+1)Y8BR3Q8kbkk(esW!+*(dc_41~GWq`@ibO|{05j@~zJ{AS zrr25et}%#&*nPx13-XKhOVELG7#l-q!TNn1A-y4^9sZXr$%K8q~IFf)Fkm%oy0Y(aj=vSjP>fg;INb*z5WIyRC z`UdwG{*Y`v{>7t!m%$3ypUrN)^HGK_)M1JoL#FsZcvh0Dc~>kx%Hjiz6r9QwO@4Ix z6VEsMi-`~7|NNr-c>pq!f_xym8=zIm9s4yr`f6Z5V9+xJDD-{i(@FI24g}*M|H4nU zKPUfIVswnxLlX-BEpWR)yG$>+`h^Dnm5wiT9$35n0D#~PoX%#?Kkdz6V5;r@0r;^l zzO9g=E+hwu3DP}?H=qZ3h&;15E&F_A$m9#ePG1jj{lI->RTKV!+lx`-DHJl9}4*wy6qpJU?l$C|G8 zos$K|>df^{+^6ipik8$Zwh(9iVWcMxNZ{8qv!3J@&r_(6}8RI|8_A%+lU@)+zwvRxi zXl#3L?=8_8)SnI8u%BSRLHiFvz>p76%i8l}XfU`ulQ*+}k|Tnq>)DrV5MSy|LLY^m zxsq28-+7k&YWSz}5A+V~|5X;iEac^p&&&Va98Kkz893&w1Ek0ik_&b^O*O?o$B zU88upI#A!(kNHJK&|)Nwz5EjTq59kU9w7=yT2>qVOHio#3DT5WezHCz_)vnnI z0YI*$V#(@vGJX%rAj!|(L|sb1xoq+y-;tk@PjZ9ApZ4~CV&wjQ`Io+P8S`=biCT31 zAK_0yD93=E*mRKJu-~%0kcI2?xqbbH_UX3vjhhdp+OR`F|HCJ0uf@*hZatIxUio*y z?|cKlqseqZ*UuDBaIg58T#5LIMErs2F(}VXJ0HSD(B`@Nh&I2Z=7+y2lS%o5Wk9Sw zT?Bn1xj4yFs!;GZeLy`R~xx!UNHA;{b_|1yi}pMpW;o3;Q)dF)Bi_#(V# zsa*1xGAB0uJ@aduo}74S8Z&kKO;glY8MXB-EzH*!-g)l-lzdkSHRQYO9_@c9gvrOf z@!$0~O^5oMiBy&Z@rlOxm#;^#Pfk;y|E7a7&xk(MLqo&EWAFcbY$e4|=7fANX#hr|fez1uLaCh-fe#O4izx!i>{s>u8eF?h>KOFsQeFE2BYg21qlSh0D zhU2^YTAx07;f1HGj($Wa(UFL6JIwvP6qW~BClbg1U{u#5z-(*XMft?*`u#OA+0}vk z2tA)Q2Xh!J0c5S%TYFJoVrm;XcX7sw|(pQk{b zn4%`dBcMmZ4^~Q16mjr-UXej_wfS@BT>O^evkE@;^;nSKu}CN6Qw9v(pH*%uV1L)D z_{2Bxd`mio|GNEYLMR{!48oE&{(pgeC4js-cT$qB)Q64nq#_6sn-4G;i;kfd1l5f) zY5#(T$3ZInEF;r9SVpl4$;gMbf+-?1FZUzKY%NSc7 zSVPz3rAf^8>zc?!L|IZ%F{HSC2jI@Y7s)>%3$d z`40G2=(KX&mA@eLGWmwzB!4nEmLKaVELXu)jKAdzOB7 zlKKdv>_6CzehA(vu~Dgw1sqkbf0rZ(*Dw6^DNtVLgm~*;Lw5FUpA&n>zS)lbt3ZXo zHQ0B;*IMu&0RW0^lKf^H7*}2#hb*1OqTwB`k&v?Hi_oL?@V=>eybPSB3< z2jdO?atJQUOZkjlP2ibA)L}o>MgQv73qbLu?4>Qtr_Jhb;lY1Y@&U^mVeL&zlK&n8 zJTWQt)xrZ;s~=VG%o%Nf)*t^#^c#htCu6FQ5dVr-7_EK(q9pW1KYPor*YV%-+^-bx zKFHIPnJ)Y(m#^6dxVC$@+3z_HG3c^xw``*Njp zeuaHo%*R-+k#IR=WHTnhJB1UN5=sWQVkkoRl zqa(-qFn`U?2B{y|Cri1uc<*pDrGD}Y_~!@4=coPrD5*Jz+cs~&K%(c@S3aMBmaW-6 zq?hoOE#2!uGeU{U$?lJR@|pJ)KjNjDwoo#nBp z&wFcZ{OyVHw-d+Tx*dMKB7dky_RVGd!i1Pp{8if*ZzBBiAP#P6h+g%VJ-_Jv(RM1B zx+Eg{x6|MD#dU|*#SoyZ{~w3{DR*__<;c4!voGX_Zno)>AkO_?8*gpzviM8oAF-&7 z@O!8L08vGpv-XxqiWeQewWB$@ZgVn~>CUQt_p6bUwaRlXx&M^Qoq70MU{uP%7-%H? z7h{;0iQWt9ms|Z zdP6-E8vMsK>6h^~>hmL~nSTe<3oHE&rhyq^W1k)9lZ@mG8zucszYd^fr;e z07cvK1miOJ<@lOVXw#!d4StP6YSzB*`i(nEdH7~k{G+waM{m+8LblgLcbsq+b%JwNhyn^tn)%45FaCt5!!7yFb$|1=##&|KHgf^Yamar>Gy}UH6}$Uzh473$X`VyCsqso4r3Z*GdaWxeV>j&Atv<>l2(6EQtJx&(fA{)Cm7He0UgzMLAuc2R~Zc8 zBNJ}d4DlcLF+Pq>(diP$7G6A8WqnP$MZg8bCMS_UNGB{7$L}qT43AD}KG*xH|FYLx z{XG`X@JV9!4gCf2=lsynpTn=Z|C~%1_!C4w5I^%l{O;v=TyG>H=~qVCr3LKpEnmX| zSE@@3*Peg2)cc?d>&NB@)h4_oM3xyjvvb3!_amZ=aQ1L z1Nw#FX%;}Lh+F|)EVSmJyWISLC96GO9DnM^mfvCV&0{Jd9mMA?-+#~F+5N>JoEF5x zxWDX=%R4OnhSY~$pLp;AexsgyJpQxOMahW&7=uaTpIe!~yJ^3N>1nyaS{(nu_>1?t ztEj&LKdfgi$b$N~jz0m8ZA5%ZKT|)k@TEn;f$@)|;s-1~w4=}U$CW_CH)46&9s-b1 z@Y>tA$$zE=^eO)Y`d(!s{5>eX+GK2yiB{*{{H_wS8c3%4ZS6NN7jVaP^T3a+QmuX0 z>+4kjShf74bz!vr zd=mcR1PBcOsFc}`FPQ+L`X0nz!Jvu1vi$7xrOAJpeDKmc6Qz4c#vg?}RU+nkfB{#s zoemwnB@tc|-V6P!I{FBf(NiU1~sUKVp?=k?dc&rcX;VS+KnYin=KCXVm z0E#a0NP{1MFADU79+rENk1Gc$<#|*ltkfVn5FdOB%onsFw4BWoi`4dnXNix;dTt8% z2d~!+AXb-F)Za4tCK8@!xX2eIH{z=JaZEp=Z^}PiK{2>HgmL9@tKa4nZpa*ID55We zJd=_1_V$>4M4BHKlu`-krofNY_e-FEGC*0_y#8~AYBYXo=v%)svW|Mxk?Z~6NV4ti z-Rk>YjNjMb?OizL=5H$yzb>K;sNh)y1+mK#GeJ!U+kDuo;QvCv%0CxFa=VK@>|f9WmRB;K8X5Oq_&iA_`sT|b z*N1%X4@KiUALRLrfjAs1>~ONVF%CUbyU)~6@b)rpt53)R7P7tQci6{x`T5?R>8@Lc zKJQiQJ`~uik6gpbeL+J8j!0c)3G$xuJ>B2L*MygiEo9lnJD}hdHX3G z6nB!p%F%&&6nw;dNlH%}d&57WpVT%dtxI|r`=jqCpRIzAs*m~!{I9^6#lJ(Api53g z&R|;7^Qci;&Nj=2L7f z)@v=1;D&u#4d*i^=yhDc1zno${P|H=Kj*srQ1weypT-pikQ^cT?SuW`+jGzT_)k#+ zUU=c`k7~dVtFQ3(N^1*`kpFZb`0D6WRA>XJtaa zT03@SR`~w`|0R>syxb4z4>$B%>g!P63`7DVwm<*qp6q z=noAi{bSJf9~sC4a^hBBszCfb{t1%~B!8TPfLc2Ry~6&orMs-?<3@bC_EZ+7>A2WW zpNC_S!y^Vr4etHeZ|}Q_{FCI{OfNRMOUqJFJSFoO{3=7)bVbvcf$iL0Srq(`~d>Jb%??M?5$#oxh^h&l9u z+R~Xbm1wy@k=jzRAo*YCE1_pNdd1aCVFeEt3RtMI@5nzuxeh**NMqkAm;sO6MAGZz zpGj|wH4mjX;>X<>PiIP=_p{iK5^ry<#ZO;LGeB;OfLSP*df_xs?jH{OzRtalgu$P* z^UwG85~sR%f&U{|&LQiW2lqydW|V^_4`umGSSU z4?%cf8^M>wx5V0#yGK!Otm%3&2*0jxsN8%qv7t}GCH;!u!Rq%LNH7|{v%f}T*l!=A z%Uz#4lU*7em5HkMJ$L>h=hN+eg!F4}f&WU?sO!lYoI22tzd@^u2=gU@P{D7%)&mBb zts`RfK9~ijKFGD=wanZ1y(OIRa}NXo;Rgw78xxzqs{QHnY=3I?$hGI({_xKyH^g_|LH()~`)l@F+h6|q z6!m4muSw${$QGC&=EVX{e@DJgwj$!EVySc`1iX2Reqk|tIqG4;;4d{+)x;a=w{R8V zJ=g_inf?q}tPD*Ke~#DiUd-n*w$RYGG8yon`Uv%BS#8i`gC zPjrIVHWVP9Z)9Ck0uu6;75b~-6Z*Y;eIUOPKN=dq14R9??yUnW;lt%e|I48O1Mzr}3b*~ov*}{K*{@C2} z3onU&#gn^QBa}#NLqIaa74(-jJ6kNVf75Wd0Y5z;h7tV)>j&v8)aFN3$NfM29Qwa5 zQtEDB^^uQol3=cE@$<;X?@W}-Z?5ltBe4Iw{Mw!jd`|KO*47_2oY$C)^!QCKOlWFiHiuBKR>+HLIV4eK=rX_({Y%sK7+|5<8_-{E;t3 zS{k+lne4qmTwuy;^l#!z-26;Kv-wG| zR`RF5X5rtG{|}RUXa=VB{kng9|C>?xd1>O;3t`Du`ApYfChcd6#Zm|N_k#Ew-_Z}j z_lo-E*T*;G#y3c4L*Cr)y|+MqulElYHU8`Nv)-KSE6h;>+I9Fb{y>qtRCb%QkBRU~ zh~XvvF8w{Kqp+E_)+h9Qc9bm$;#0gl!wk!~ z!AdEBXc3@T4v_~+)P;KEa3|=$tPx%SRDge#FX&_Er06P22lic%hrh<{7+ypC&Fi+- zEOOg~2jQ>R3_5JXYAYhm{O!?~4Gosez6y0q!TKsP6bgSC-(`NY@NBa$8vxBKS80PMG2m|blGX?J;jj35E5ILRfAFeAQ`!4Fa@f}wFrdiUu1N3G2onIuupl?za>DBA&WAP({d=L7wq*oFlp`(2u)PKpYU?HWz z(U(l3VSL-VyWi*QYY*|yudM-|Qa-20hE~H}mFon9V)Le|{NmQ9Gqd7+5#%kgZdq;t zaqS{4k6+koZYm54n81OwTFxYeK?#31nt6xaGyMRdCoX^-e-~dCjd4B($6Ig)i1mwp z0=3G|pg;`qOMq_M?g^qyHv$0g2lxxjgIz>Hn`@$<_}SYn{)3%X{;RqOQE+++2#Z_D zLw`_w5%eAQQ=6~SOG~GLM?HYZ0Q-RSW2bk8_$9jKBK+4=S_@6VHOP-#R!`F)*+-AE z|6o^zxYi^opr&6i2AANd&k($R9<3OJw${J`&Ss6{`*TNuo`o<@JlBU%I#oph+arNaDE9 ztg-6A9^fE|In4S%y+}{xfN@q`_A`;~AU&0R0^u0~=6(Cc{4d;><3XIEm43DdSb#g1 zO80j#E*R9`lqabGhtYQDzhqbHkq9BCqj+k`{|QY0s|jB1v>h_d%7~-c-(5eZ68NC;AL~cU z<@Raew@j-LVBV|n!|+&^58EF83D3Kb()gI(_579_=f|L}JRbQc{F>nN2*9(UW&X?Z zxbh%ln!nZ;1>Rgh{)>h0LhtG4d>N&ux3Nq*A9soD4vTRTe(L=A0`?;qoyC{Bb+J9P zp#UdM>KB_%V?P4#Ov7d6to|AGG56mV=L8$5T)H6puC(LG z(yEA^??wD;6a7upN8YITA^PAQ*T?7BHdA9MtpPl;jo^M!^SqGQ8xmVeh=zY5(7rr{ z*;g55lb}QTHz}IJ-xcel`pvRGYXd$uImYJ_j2{XJXfAQA$5Yg|AU*2APeWmL-TB}| z`zDhg-2s>JiT;V-!+)?Gzv|A$1ZQvOKav1Pp$5Mf=r7jP)HmKlBUN zO+FNE-u$JAtzY!A!h8D9nW6whGf=bs8;~l#U&ft=k)R*89>~Uu<05{G@uNYKT{Mq= zx98_#`wGq?KAmTlKFNC3L&L*0_5uR4NpKVZAwef&n7N$-j#I1fv=(SP`0P+@43&8(Ywie3mJ#QGry_ z%S2zuU#!+oUpjsI(%hv|7Jb&~my%yJQ4h(iv{XVnK+34={2*rH)(1Ef{sL8QeOM#; z=LWWAnZB(;6ZNhH--|T?*oR;0MyLoXfiWH#nNX~rSIU%g)PWe|Cr1gtz2p$(Z)vRH7}3 zwk=cApR9b^Ta5UnmlRK8#Dfv)Y!0={aXp=V28JXbAaqa~!kH%^GgXLTYtv=d4+4s*~=jbQAOBG1v#9}{S z`}3FQmuii_MHzU-J2U&+Tid1>U*+iJBq8Z{OfIagLZGxktN|Gm#=lH#(A=r+rVs-y zo$Aj;6Z_3R5e}b1lu$!Jnf<2d2LVP9Ufo0M!vOhm>J{t5{*cGFV3ibG`U$! zQ5J}Ni1{u1pF)4q1AYe1TV`4DGD8wRBz{z3A9ckC5dXR{zP)@?NA4a1qaVZnf@ANs zD5s0K^ABWSyPI-}5u&$ydiH96mAi=I_O~7Jw;&FC2rJlwYJ`!o8~R6Xw#rlTvC`bT z=s&BI>B{hLf6lb*bUM%cNgaf~?Y@Q2e@*dSIvMUDJL~+vd;m5$8`)AVWmJC}o}Zlf z)Wq0m92dnVli$V{GNl*1LSLjs{^xaw!K^V%P&**_MZ0rHB*f)^pf)%MAXorbEb%Dg zFPL!YBuwCZNX-8ru<7dSdl!5fvFjE*E&n=%#l(Al3sq#zYpTS5a_0T@Cr2eA zWf2TA{W^d@(}Ge{q8s-A!o3F#zufd1^@Bd}{0`YKKN$Zi`7W%p6Av9adlnRA|GJVo z04DAZn1G(S)hBL2Kc}(g@_T5xwjSijeMgSzK_%feKz@Hg?u8@1Yac=wLh)P zrN8kuA=>C36Szix))acS=k+(CpJ4jPW_NrA`!KqT8Bmvk`mMl^phuu%`{VnW?;{z% z#2Jq-H_1C&@NArd6w`KVlI_hGn;#eZMrc+0Xt2SC#ERYA^0SkB0p zTqqyAGOq}NId?t>8%*qh(gP-rtoB0QEWF(;2L&ge0Avtu$ zW!fIo5K!aL|Ac z02#&=gQ662P?Ybq}t@&uHHGNG;K_^oixplUfFHsM>J2l1@9}|=M@$OK>S0o#RJ_3pdthO<@;B2 zB=&C;0MI-mFWVITwN3$aZ73 zHtt2vM^fwmhugC=r0CKwiGBmeebhH;D0qyI5y4-ae-DiGB6A|p z>=7c8osU2T0gRWh7u8RZej)#oSJwfCI)BgPf0Z^Ne~o*2to$fsZTWm(HWI=#E_eapb%9jPFG|_iuS@@RZ`8>kA`hpT;aUD%z(8{8sCXZ!q}svhC|5 zY?ONw|2aEL^*n2UhvavQV6p`L!}{aK>t(tj`=uj2PKAHu1O>Z>5V9*M@JF2=CG&}?7ZN0ipG>I!z-=l&!(NgOk})H6X)gL^|9RvyGV`v-rwuV4 zlP=s3_&4fNw#3=BXi+rPFMEy3EEXVgmB~PU6x&TyDAgPK?;E0@=zi$&EJ3d|{!(*-HU%o%l+fI&3Uir1+KTl!Y zq)62w0iGVLISB;DHyz>|^^-A|WDOuYhN5A9wO4%&qX#ksp_S zJjQ&1kL3C!`Yj^NF2-LE)yF3Y!tx+cisuk-+tMrMM)QD~9 z{t!@l4*#pMXAlY67$NsB*MphqqnU2ScgL3$0WdlV!ZM8nxt~TwRz)#MVt{e$ZG!uBj>m#~SwsXxc_UGcop{%+K)z z^7jiD{rX(;(b}%_&{F*KZ8#_6Z3aKdUC4&--amdN^W%~8rJsz9{~V=P4nnwyUYTur zROLJXZtmsT5cenk_>SFu4~**e8#o^U^2@usM~j)e}VlZoJab|QC*=R`4!=8$*W@KGfN-z zr6|>!7j&$H@l|RjL#o6V^cM1?&Pwd#rEnhp=vU^{U5{=Ze&J&6S@09l5XHrmLxCWv zl?DIgv+@AUU1L0Zyd&5B|Ky+jlGoWf$|*14AIz9(&paX^j;Dy<0=SlPB|CwP5rE&$ zzxpK$7XyCC7dev6J~ZE%x!A7yA=?bqTWuM}XW+F~s#o zmlwTiDJ=V!?ycLWLR3beAN!qi|9I|vHmQxOpub#S1Km|4boz;j2;86Q4q*%ktNVld zW5Hnhrr*vWc1AxEMR}m9{z0L_*j4_{xo=*!4Y=5rTpHuvGy&8Y; z)8mK!c63zyO+#1pyM}#83BJ-xWCW6Zh=+=GA%5%muD(7SX!UJO{$+8rwysq)ej4Cs z4FIX|06c5sEyBMk_Jc{9tpmgwBI`_?)^3{X#Osf4*v8Z(FkWo|c=4v09_+ z^U>OCue{Rp3hhte*9>Y#x*PT1_*L;51Q<~J%C$Q5f)AJiLI0Yl;FCsmgwovXAO2iM z8-^8K6|SI30iHB|%!SF{umiwu(63_NS`#HXvV;JteP4S6{FPr|;IUTjApCRs-FM>I z`+g+_E^ynh9n1bFLx6BYelTB>`mA5|2aa7<+_wWG-~;!*4i9mNz@DI={GckX4tx<3B57x!rxUu5sZ!CG!oZV#Ct{1hi3VzD_Ix(*Dw3~-cU1Wwuu)OBvLQs@Bo;J^tQ_RO6|)fBd{6~I z_5#m@jpgFmJAWS3w`5#OaZ4T4_>d1wcv&$%?@8pl!{vL*!-u*3hx$Y5Lg zf53mBlV~3C{1nv~e0}-Q=i1!T(`OgX&gu*Kr4rBoR+c_iKzqcgB};#@K%WGeTAlG= zU+zP{?RzMp%h|sImQg^sjuS=t^I`n1ci!?_Jw3g5a=z}32rZ!X)rlOJ*Dk4WG07Z*czMS9(rlMhfZ;BaPN z6905t#Q8$N&+2}{uM~o%F${_p*Jq2eAqxw+zieNHbka6R=ldWZ5}1X>w^ba5$C&{I z*Hm^}snooM^^yE4`Q(rL%?fU_&jZ$xRh?7dSH?&9dC}+Iwb&{kPVxDBng%TX8TwFr z{ui-axgPyR?=Q05{~dbd+37tJKBieIkK_hfPCYb`vk#89GOlP!b{Sh|7TQO+8lA@` zqjly}Vn5f@|#pt~0CE3DNXTEl#J^uHYa z9(#D1a|De={Qz=PGA`_J(`fIrjt0DqSN!}`q5)xLYKs;2WLEWSY{knEQ=8vi1^ z_ds^{#KgX5fR~`YS6-aP$!CVS^=iTFj}Yxd1r4#g`^oi5s3IFj1;}~rpT#F@emfio z020Mt$&dHqho3bj%QRDs)ai)f_rN(2Or_fpP?Vp!d_Jtoxf95^EO>B4;feV=tJLfb zZHd)8btEJ=>2=6QUdxd>=WJLBpbZ?6Pay-kQzx?u_BOg%Ka*EqJ2eth7 zeabyzm5m0_Q7GLFfa((_|3Vk95Se9k8v8m@GvVlZSE#aPQ7Br`ET`zv6knFuK!F?4 zciK+!Q;v1{i|n!h0X*az$X(F^OGxRW4?YRf$ilfZCSNK)%uXmKeM9sn!j0#$?dO}f z9GIJnD8AC-cc?Ceq67STXnlTQpN!zY2ES*n%V#D(nuuX|%v!8iAIl%-{}bcK7m~Xm z7A7xh&4Hcf*4@}YssBxE+Wd=pfRj(5KS#*EApat7`9a0miR^NZfC7f)p}f3Ito zWm~NvaJL-b1{o*efc(xT<#&=`NB)oYN7k!pZ=$!y6a9%&oM?EM3YoDrcsTfTXvp`s zVgpOR^iqo3i}P1p(K6{%z-~5oItvJLyp+%9RlhdyAG!Qt{8P62lGC*Q%AdT;Q62^; z2&19=u>$>qKbn2xb_K^C$bGINAS=I;PT~V~euO?}_Eozc;f5O!e;` zzr_GJ^e99#{SwZRcUHdi;1u~49N*x=9OS7|~57{pR2e@DPcK446+0c4M#KMVRQJr&#(pLK01objPP)-Lcb z!3aNeYsn9Xs{%m~oG-zj;|~q?;PF2xPfOLH{-(mG_H<{z(18HbRe--!nx1{G$NNS8 zkT;colDo(GPtcFR>`)BZ1}`-02mFMdr0%et@b&0wM!>K%xVle)%`V`x^$7wzb->8j zD7V{)dyakuhc)sqmgDQtQHUQ|dzoh|_$$AI zf3Y*|*X?{~;!`54*0vI3eK-9~0QQ~iBz+$Fj_C7c1l9gCO%T)}xAvd=Z*0Gv^n{JF zbVA>8yA?lOeArv^xefNQd@OMPjsUc8`u@Ch<9nU01)wTwOK+?HnV<_2(dlZ1`fzRrVsF0yibAr0O>%y z$HEz$e~Nf?h3ZrmzGn6xt)7M<0ayBsR!_rl`Y*fz;*d_~Bd)$ISxP2ZQl9>d>X!>k zdxe_P0Q`c-!;9l1BYdZUFLWn1?4Hox;oeGkh~A3NYr7EbdjnI5^mEzP@$P}28RQ=h zr#)#WgI7z6A7a&&U>n!@h{nHsC0Lpm1L<5;epYB-cTWsG4*jC+NuT@o1dv$^g`_qk zp~GUOMq~d3{Rn_K)^s_(1qRcndTiKdl6Q)LD*h7xhE9XcHT-8c?w>zUnlsN{U#mBT z{6fFWFZ}5C;o%tPZ!M9Yy%Y~Z*vO|DOt!4v{6(UGO%0HJ6Tfu;0^FY=01GBKy&slK2qT;Xwd!!Z_sZlx^y@7 zU&aK_tdJK$yyxMA8o-NFDP4u(Nl*ZQ_|0CqB->dL0h&{HWuHmmSv1Mp&0n?6>lA`0 z1oKCTaOV>Wyue@G*LQ>0Z}`V`zT!r&MfyRe}3)C;FS-xQIVd~!lR)7`)4&bG!44i{A%El9fKoVb^ z#(rn1rR_S5fDF^Dh=$-8okR|tQEJt6N1!SLV`9aB4zEgprikvT&7<*ft& zrSB@3T=8yH5L&CPlK#pEa)@Y(z{Y~(8U0%KqLb!wu7@KH=%(Ql9vrSN*FOtLMHm$HPzaxfhU+bvQ@p3HsqEcL(}EQ97Bl zKjle2j=B6bBIM-XsMfYznUANc#23!1zBZ3N z;t?62&Ba<3Kco1%T=`q>{%^wn^NDDsFxp9Y@kc}e2aykuki`EHlAuS}%9qctp#Gkp zz3;tT?*11CGw+>g8f#kJ(u91E6RFrl{Ji*|L@*P>sLzzy+hP?`arm)*PCfzv z+*|NT`b5c~l+n=OuNUp~DPru<&n&z|@s;CRVRyYe`|b@&uzShmuHKR%IQ+A6v~gsT zVz z{S|jUTRQz-I{iNTBiw|0tG+6;06(EG+8Os2{E#1#ooPV|KnTD~vgNWW*I}SxY6un- zhllbVQgnjgXJLUdHS_c3Y<6J*T;hB$pQAIwc<%{Rr@yA~Wyyw1m`IP&e}n!3{!4}M zW+GyV$hV$OE_1C|fZrp%nuSU|>NcbDVrzi>{Vd)3P> z9B2IzB%v?S*e$&ytiO-wp5ywNHw=WhJSocRh9@%ulKt}V#6KMY<^zrhqkfoW+n|Vk z(bnJ=lsY#1Mx0yJuFjJOpneGr=0Tu92X+mxBeTQ=+GpMn2(x(HdN4HTg=`fWpPS$E z`0U?W;7r#o2SY}!L}3v*hlXaAAKRYHm)UE;OXn8~e~Lv@|I9vNTAT6K&XD|PY7$Uc zOX>(Z`o7Ii`>=sR!IS@P$)m9Bi||0K)aQ);#Wvu;WtBld@W%>x_^Q&a`bf+_nz(cI zrm05#Y+{2L?WHDHN{sjPJh8CV;BD+dOz4gJ zOE=t~ss`&-9~J1Q{A8O@!U0a*s}CRF3g2DVzJBKz;yW+sYbI-l|FR0aj!{3+^fP3z zL1-ZQS@w(%ZL7~^bU+jFOXv@lI8!R4J`@1vB~R8($Km1PTdAy6B76W~QX6w({{zCz``RDpaN_At+WVgCg7DN$ICF;XXUYFU0(`~=Goj&z2a`+2_NC#qFus6$K){}DaSf35mQfqeq|+)=%mUp|+` zMC0Ul<*zI~|NOkLToFWPoF-0w)a=S zKMDf(;03BjJTE-gan75aJ6WxU-cY_7AaQt&S-Hp#Vis5ZbH}foIQedE?$=Bae5O7% zh_&UQhPe~`GTDLP1?D|PKYW1$Y=VC7w^SrCJ{f`4KE2JReOcVxX;J`lZJ+KeG4SB$%nM_5B6}MAxIgCOrzLN;2VH_eMrSs(%Q7 zNq80?jeNMgzM!%A55dt^Lb}nPSU3TOUB_SL2Ml$^y;zGN4Ee~16V`?02UyN?(!Z(S z*4DIsy^(CzGx1g;b$o0Li?r47l?(mPFOG`lMhd(XZiK5B0@GLg5(e1lva327EQ) zZ=@sSH4n&m%p3ThKk-KhFb(+yglCHevIp!5p7IY=o5a0|pTmFEwm!(u-4hOfV138O zhK+tW`G45(AIl4CuZ(b`p|URo^&@3p6aOx#gW|L@-yIbGMP&Qu1*0_lWal)#s{wqc z@Q$S*V9tL8jF#s*FF?Qwf&WPPzcW;zA0OBG7@9NpXAEk{3OCrFB;F{l72u@JfL~Fb z-XL#L@N2#rtPS&lzEPROv@?+a@WWs7ZEyyHfqW3Xrw0;v)8kygv+MEBpJ(E8Mgj2` zKsBP;VkYPphpgYW_$nJE|3Dl1?Z({?wPW9to-*}^)eDvYOaANJrB=iLZR{JdZI3HH zO!$8#ewh-wqc(ry52izV!UGm4fEwDsFCY8!H&vf<57No<`C8Nm(aOv>B1C|XLHZ@1 zI4SQsegyi__4oz=5g2s)tDCs}<$R_*%NH69brK30BC@fd(787boSFLWEqkF)&@YYO zb{P327{A-$zO`O?do=asXoVWboUy|E*Iqdxxwo)bnl}EnBEOab{ZD*o{44r%%AaYy z%-*lG&${~6LHy^V*rzyuj37g2z-9i^`^xuFzl`?q-SC4O=}RV4QE5s!K#;fDU%WE` zZ3BMpf`6}Uf?#VXZffE`US2#7`>fGl;9uUu0;HQz&(#t?**ZiIc&|!rDZcC68>i2> z>Zx20X*TPZS@D!UQndvAnyh$FSB<@O87+%Af01~jP@k4gr@T;SIIkF~WPbG;)kmBq z_L$I*g@w11$=Usie~-5jpoZ?>xt}AVoPL{e`3>JDzXbM0eOsh6j;9KR8S4t^ERnvC z>o;;Vk{BPr!pKnKg zEU2qKd1rMga#i%T*-meh0EBsv7F2%?{GU9O1eU(*{K)`&exC9(7KSJNWXM;E2Ma#Jy>_6He`3L(a+}(#SVLmO_=EC4ZgL>=`jR8K)wu6+X5YcEI z`q;+$CHg-$@c=W``8D;qrpEeQviRzhH^|r@LlcBQfOd;J-#C2|2Y220!$8wC(FX$| z6!~r7|BcuGEBa&h2iX~3_3RJHkt9Ak4Pd+cvrYS1Z^TZfwtRkK^H(2I@t4WTui|M2 z0FX~R@R1;3)VufmH{1WixSnam?@HgSUspgq=x=*62L@#Zk$bk@IpsnA=fO{Fzt4sX z{@@nW|IlxJ7{NJUp30u{NQpnhJ|*~xKU}J?Rf!?;#!%fsnoXvqah;oG>SAp!aq@FVSnwPX8Ez;pAzgzLz8_A>q$Jt_>}4=JKXa4+(@|X5mL9i zyL*nbB(p>6_ol((^2kU@IlPR&C)(4oDY{1K18Y2Fe+#Y#4zJb@BA-A#ECM9;xY)S* zuUPSX&RBvEc_a|QgNY5nyijZ^kj)@^+B_&Ugh9WcoAgQ00`w5kjsE`pa|tNbT5+DG&UA>v(r zLGmT3RmZx{1@0@>-?4UyZ_+QS@?JU#3FLSBrIQb#k4`>1e!R~40d>I(1fLsV|5W;m z`6sH}0Q+ahKUAH6;zs$6Yq)y(2HJlBJoxhS%uh2AXlnS1zoxVVAYcGc41qtO1t1`X zto4_CrX$QNk%|I5=DUoDX1aK1D*7t!@Pa=`Yt2Pa*iA0s;Eays8l@)7Z&f&7L2 zM^>4*e?HpxI@@{y{Fdb7Xupb(2MX4EEv;8`Z<_s%{6^qI>!8M%*+@CZHIb@^^0A?% z>5v)cWj|DXV;G>`0z(&H;LaD~e5@&+uNAWI`o{LLLbvh-l_-IP-eML1swXV0XNkWL z8b%Jpleo|GtrZHsZ}DU7S)x(B1p!qbhqAd=*N+PFPl8Cert9*Di6i0JS=mWEqAL_! zCjuoiTvh7nl7IS+mpY}va)XrJMc=dpgkP(<=m2IY%@-GDqpvY3ITZU?Uox+YfI(=QI8?=G1aU!l$j*4CvgE zb@g+#KTdu|aF!Cr55-=TO25{(XB6Ldx9T%+N}U?}!vNu21nJbCc?KO1wo|EFQ;EpeK^aX1IJ8B;X#W3iY$dM zn)yifk53T)a|f@`9XKEv?^0og|By#*&G?kICZqj*6p%r^3lzN4ENgJ1 zeR)2fA6=23j{U4ShEt6)62;FJDxx3Zmgg}Ty`icvY>*&p2ll=l{_ybK9o#=M$4p%O z)!Y`vKgh%R73h3?qt*w=b2|{9U())x1Vve-IsYu;Y41a%5H|eJ%sdc)DT4(3s6LGo zfH|iX_`!-YDC;!eGHkfuU&KM}_xN3Z%RrE5_|GvPfgRwOed+mVKES^7E|`64?);m7 z^CCq8=AH)s!K+8=`c;ec3Rs~h#vzfrzt_(>VJhwmvLZnpRl0Hw|sh^q08 zjBx&0Y|G~Dk`URyMHKpdPX|cKl+tY(}$*~#o^`gJ<3_Aln*dp?@$zh!U1t1e~EUd!BNKeiT-@ABo|!FZQ`=%<%l zIQ`nC(}UU5r(eZ_h(6B5(Y~DgKzzCI2j~+Fnhgg)oKbzb@lk$@Q||_&k`%>rAcO2n z{8Q!6b~of-(;wzk|IBPujF0%S<@z!~{Fs>t02AYHqAls2y}j9yVZ=ADQhSxHvA52L z;DL;~$>JAHeyW{Vc1X?fhyLK&!UpLtfVvkAlHV`K3)o zLjG6+`Xb{D8d9(dz+anRh{R;xQ$xNsvD_c@t+Bp|#HS{)*W{Nv(P*xR(}Qz64ufA@R4L7If>EwdhXlc2t@y$E11YzZ zoR7JG;l#1qVBS|ne}nZS_|<1~DuH-&mF}Ql=UdAC*YJ-py6gJ8;&YL2`#!OIY!va^ z>A!A$(Sxtv@&l_6V8x@yK_uc6ki5%vS! zD%elzJ|4;S`*AcXPo4UN6Q6=61{H)@-w)28{7eNfS3)Uqx(YIhqRrBI=Hb>?|3gHU z5F`5oYp!WYM(5cSrOIcuLERqVEvgR_UZB1yh*YY!W(){yJ1{`-KF zk0k%f{*HwWA!7;qak!XC>3I82R%ZkJpLqEfL6y^JW2HInawC5V+F*IDKLWl6xcTUTBD2j5WolFDCOLHfG8x9#@N&rSwHfpuwS_VY}G%t{kPp$el&2K zf%>sUD9Gry(2tU&qq=SM4Eju$#YaUs)pUgTgB!00zV3{q9=E}3Jk>ueY>h9j(dO|+ z-UT{PJq&K(;;r%dExvEl0UjI@J4s^KnQLXeO6)P zvuAtwyIej=e;3R$MtHCKpZM_jLh^Mq{3qbs3i;aq3-}AYl7D1BS?BS$#ZPIsao4~f zWQCE4)Nu#|N#4f(KupjLFy7KcKkR&MXFqoPxWzmtkrKJ{}%pDyys;NL0fB0_)qjg82h30n>_Rz)(V^u;M<5#%4DO+ zmooCTN=0Xwk>^(pZXp~!qVw&FZ%BO%lh#i!!HRwtfu+D zV7!%~&kcQ!ZDON%>ly;}LXXou-E8f`zT%kBX&Vb)3?xoY1uJjMrl`#YAg6aBb~fy+cU z_15XHi0*PFDPDk&?rkPyi-8gR%d8FD1^zMod$}%{cBFf{yY_vG=SY8B^k%}lT2{9l68yDq zoNjN!{~U*b1AoL%#mD{{`+tq#JlTWs?`{xzm4G7og!qys(I9;Zz8m=)CctQZJVWMT ze5CR}HtGk<20jJ+1%NSo{*3uQtbQ^6S=B$5{fnbVVQ+;3XN=|&Uw+o&H?97$oxi2{ zO<#K_3Ww;Af1-7$k0r#quKPou3s)^Rsv7tQ(usAUyVJ>t(yS=Z2R;26ujj{>6V0KBdpV{mMsYe%f=)k*y^Kp+inShWg&r+NkBHvggdi!#|DxZBGhd~ zmk2HwgreM~cBuq(ovOq$yOW)o-Ac`!F%Ds8Np@;NxNPmz)=Xl2sTpQ=_QoMhjd7Ij z{r#W!v@FBDr@LiKr_a~>KJWAKf4&~%E&2n&mUL7Q#;3S`t>V?vtz-9(jg5Uz#0~pz zKCwx8PAZ^d>u<i_xd z(qd|W5_s|0#^%waF`fY+M`zNYzHpTgQw(PNV(>j0%2$1KkCNcKs9S`DndX4vI z%NE6kKMlS>;>>9iunIYl`ibx}1gX>n{$GRpDMP0Q#yrw({N*bCwwFqo%F37WrVq44 zTLis{AKByg6t334ARz8`#RrSOcMl~SVeq#M9K5=pl6V$Bd{D(-A3^_z)Aoa3oSQut zEPr!hg*1+2g7Y6@|EAa@oy@S}_sH*{FmZC_y2~EZjQ(!@lakZdjnY2}GFz>W5}n`d zZ^>ZW&-ji}IA=jJDB_PQXgQ-Ch(hs52>saatXwjrc7gx6`Zcm{^7Ky*Jv4jxnms$u z4}VKYH$pYiTl!G|ZJ@kpOQ8R{`LzP|rXMIc2n!mN#F&s5M}6Bg+P|Y|OILbFw%~a* zXnyGxOxrVOav-FvhfR%}dych28-5o5i*E@MOyX<|_cjKn(CsPFvC%TftJsp%bA8C) zr+yRp`;Be8#u#Fs`%f^tCIOLh0rczQr<0;z`2TFt^ozv_shG1>;=hRf+Oxd}7S_|V z|5JqLKpsIYdq(Sw8Sq=~wfF$)gA*UX{qT27o{jQ%xWTUooFl*%dm`p_%*AWl&O%>~ zjEV0^mlLYKl03l!*jS#^SQeht12F%JWpLXx0ZeE{a}j*bzjG$Pefp=Z=5Kshzl-5M zV#rWpoPKt}Z>}w!nNtA@sW{9J3DRQ!(SEp`^B~suC(5*kCq#;sr1(zsVcNq}B4}1} z3SP9oZ%uvKFGTpKR5w1N--ZeTol{kK#iN;FuU=`mygm zG=AV`{orR&2@ddgY2Niuk^6@`fe$w{$LsaOr2kdDfxq~``lG^h*3@_Z=uTu@k}}c!AlT8!TMOG&-l7z`;<`#1(r&iknf8RrzJiYu>vJOhhP=i*5>u}QL+Bj zmc6I!K^P@#v=RQw5IQTg>m>aL$Ul>THG>ta`pyk>jyB^93#Pb1?#aJ5+H@gent$Uj zf)Ny-!r)LGdifmoXR)_K`B9}_QMUQV@!zqgk-qkmA2KGmyz(D!nCg;$1fEb?32W3K z{_09NxPkp#fQm?bdW4@;bb-ZZ7Ws_3{GdEsLduV#H>Dqu;8m&NLv#48w3qA-inr~^ z9V`-MAnBW|7I;PW74e~=x`UNew4p5h2G+#<&VL^*stP`kA8AT%d@PwH05&_!&RWmN z$n&Y}U%C1bvOle|S<>ZiUG)!DC=f0Evqk++S~|Wg7wX47p4qXts`HQfDXPn29d-#>(TmNCJKT2+t2fF$*IRLu@)0>U)Gt9O*!%Do3p{{uGGNCyNfR6YNS10^A zx5}SVf=9%kBK-;aH2zfApSXM-{4o3w=iwvKGaCQq`O4`#J|4AKvi=vf5nh@n@$Ybl zzoEFjbp!P=O#cELv*4XNf9CwVci%V80=WVGgD3dV^C6%7K*}>jZv5H16r5Lxw{k#u zKK}0Cvx@;9xGxic@1cL$3{`__;;&CUXZ*{R--N!k-VL^8Y3bitqu*?<@uaG>Mf6cs z{X9W$Orde^IlgY4SDeiRxdV^=z)!m46Yw_+-*w@2j=z}`%_bQ6 zjoX$ry2)0k>IYGOfR*W%D7pgtA=z~_-F!k{L|=qIP(uLdga1jtC|{?g3kl?dL+~HJ z`o_RtuXkQL5i&;&B)zGYIC-p;xzh1&h8zK+r?w?Jk0)5c>*=KE@FUb$*hd||(!7;5 z4|pO%FS6g=KNY5RnBW|=zIIlZ^4E<)>i$*!6aH!hl=yOMJ08>)_6uD#0&>gD^fLgE zDE?)N-?M+~bgb}|mos^hjr^w@6L~dhO|ZTy_)jb6vgfix%knr4DSw6zb-DcTmdtV+KyYErLbH2#u$e8-Gtg9v7-~Z3ozkkafb#Xue|~Tl`9}I8vKt!OqxwR#g<_5R?W{jD6XbtRCvb0?_+k7a^NHmr^auS` zfwRQtv!6Wc4)GuDu`pT5f91|>&mFh$ZIbdl^?$%W$$R|G`0T%i{b#US^v>i}KLKI2 zy2azjuV{ae&1@f>f)w;kxBbye@INuIh&9>z3oAx@s7@jL_k();n)EO34|^G|5|;%y zRL>vGa|T40>8U0^jQwAZ^3Q|z=7jYZXl`y#lV7{`{$~rfINU+1E$6r%`jpnJ@&wYp zD(9ge{0AEnk0Sl?o-ls0OjnA<72?AVgc`qOV;cWD9NaeWzeLuV$Tp79AB3aa@9n`3 z#lMIzc3j{TD`9o~@h5HmG4XmG`7Ik zWGOlQn*6*z<(D}8jrE6ZRdVw-7kg+_ZjSoDcw-}G)13X|l@(<|&*arvE|J)Cb z?Go~;cisQt8}f*e;-Mcv-*x$h{M#k^uXz!Ts6Pm60tB)-*>O{eM}hx(4BASf!?=&| zU8*B<4&X11u<)&LF8N08zy}#3@iGDWb60Fr<3`blkYJt{{5`ivs~;-~`PCz3)t z>+9n_uAt3W>n*!3LgL$kK>mwZEWUoTD&MI#a%`*TT>z%3fN~MOGgZ;!Lh|e(K0^jH z{7)KEB@BarI^J=QC=Cli0LG%fxZxY(-D(g~EM{ZS2mMi3@i*hIu~<}qPWZLgKy9lL z{MRERU!n4k{MSJhcouoWDygC0?k|mvn0DJGKFr^Mu4RP&h1nO}U5pTUq(4^hde+yT z^YJ+z95M(l5Z?;>@;`m=q~jmZhwzOV>~e|ss_a+P8X>5iC-|ZHyoyaS^n)BP_;PK3 zQsNVbRmCRifAS&xz~tka=i~a*st=+DTWlY>KF_y*gj^6dDezp6^RGGHi_kI0-wn^w zvk9g+zPK18t!p)ZGN$^H*~PgJ*n|2gR2 z+3ya&U=W~x+;z!ji9gZb91^`)uWzHMt31vcw`Jf@@%SsVvx|#QOFwy5?%jcVxQM%S zp8BrELzf6@T^CmdEcz{?PfLR$`1%g~2jk|lv>Xhv7b~on?l9RtFedMuJBi4`7QtK* z`j>5I98~p1;NJv%uc(SYJdgsAmpp&lW7r3JZL|Iy;aw*RL;MH}LzD^nr5Ept1E5L6 zB#yl7d#!J>vfmtkbKNt!M@4B${XTc88#Q-%xwrUhuE5(?huIIE#~?q$ zrz^4_7M}SZFTC)z3idnwdlVnn4FAi9o{{z%{n}t}03s<-QU9!B;kjQrJ&*Arzib=A zal7r`e?R!oF$w;2-#vTgkKYdSHh!yPVE0G;miidTeouD%p7<8}P3Q3qo#=P@3#rB@ z0no6o=J2oDep8{Xer&0D|Ain$4=%k_|BvKWc;HD9uf@+GUsn?AsyScXM_8X>Hx;ZJ zPOyy3zLb4Y%T|NzpFDJ?dkX$CT|A`rP^CLdM~0C&;;-RL+3}^pBXp9u0QC8LkphpB zoIdLH4qZt7=4+_%G6Hkt>ugQuX3Tp&1ir-l5?%9~=b!&`E8le5_~SM80eW#z{EZkr<~v`Ih3a=H9)hFsA0>5r(!Zan zz>==5&lA~SFdz_A;ipD?Sf`kPy`SC3{ab@7OHRra7(a@S=YDH(fzF5Ml3tX~W_*q0e`nJ&>+B5oL<^h3qJ)W*JfaqAoR>vi}i_I#0k z!YD|7f=?LfI{h1#tKx!spK74pnMd`4<=saX{Ahl-LDJVG1^K|vW#3+m>w6Lk;7cq^ z_-9M!361Z7hi;&avpD`J#;fk&ihojnY8bB+Aiirk39J0~#)rk8#D6)^23P!}YWTTG z5H-*0i>w~c;W$Sjsk+m{Q1zxCFv+IVhw*L zqxd$q%y8)RyLVy#y}g)Q=o3^Pg!ke>Y-+lZ+w*xUNYlNAznFF@&PB-x-M=Y_j`CH% z$^lvuKSi$2Cc1Xpvxxe-e$5P`J-GO4M1WJWjR>^rSsC_l-?S5_*uj_nrxqsNCHun%M)IR5ylwf=ESAy?g= zAkzgKhmR{Cl1>!x_5cf@<|)4gTul`+_>YTooguywU~zkU8Mq4OEx52-Z%DGT0UgrSGTuc_|-O(`!43Q#hh zk^fW!<>;$~0LA-dALyU^5>SYg<#{>3?rXke-aF|xsTAxN6<-JnlL0+~pI8Ea#2-8g z%-<<|`qT#X&oKE6_hEo*YyG=uut&LA-Ts0`&|@`z&`o{)NBGb+^uze3)!k^dKh4$n z@Kt=sM6Z!Bx9G;z4KC-8!dLT%X{7X&=fB~1WzPP1KB)>Q*&o0^T>N=sQ`)BhiAVc{ zvC@;7AhQh>b$u+7&+wP7bhf)7|C)1PCy4WTj`Oo1yWsws`yf+j_Rv~b-XWkX1y=D# z!~gb3GoP{gj*?Gq301w>*`gvf7=R}{mVRHO3~Ww^X~HB27DRL>zvqj79l~P#C12)B z5rn1n7u7GZ_ypBAa``cqK=;N#7t1Fqj>a8QAdUTsKgA${L5x^@xX2>eNy=I+Vxjv&r{b~vg?&%Kp za`Stpf^O)KrKRu$;$N+PO0;@nc?+1d@zvOwoI*ckeNt3M@?|eXu-EgSe?F}Uef?wh zFYf)+ZIh&+u(irR?GnhuVh!I=e-H_YM3eRJ_PkewKD@0TnOBUwSYVj`&0SH)--q%D6gGAA@V!3)VyvT`n&M8cymMj{7B6T znb~;IjE5*cAhq5*c|Ge4tMMS~J6xW4!3X?n@h`xvnop)ukEiK?B>$K4k4!E}cGJEd z{YnFHiYrk3$oKn(XQ_`2 z!uLdqzD-ZWxc_*b6PL-7Y(I_?6#4fBvDl02O95re>%Y=JBjr#5IO30%KQ=A~qRr!* z60ebaBH#!PcL*C_wfaW*XS9gzqf@ei#rw$6%F4e|VQ|s!ai7qFTJxj&gK7Gcuqi$& zx`15;6#=fqyPf_}+P(`7$-x%F2*QM}Bx<#$?xApWcRWC3zN`VrKmFEsE+C3qsA z!RJ1-Ke|8Npyv_l7~LN?I6wEzw>3YSdDg@fY}yGw#hp z&s=c$wf0M5PP`^E@8Mrp^r_3LE2+@l0m!Lhqu5n+_=2%PH<_z*V`J;UQ=rj4&p<~N4 z__^WlH~BuuSX?0hmncV5Lc#ZSyUekMUj7wgHk0$5nbT|2`iOO@u;_+P zn;~vr6>=R5k^MKsRqRcFGUlJ-sajXlBd`tfd^&G^V>}(**~xW&un~14-MFhjcorVO z5O3^M7@oLmANEhC%j!R4@Tfj5g_n4K=mzoU3heRx$h^nIkmw-x7|Yw?1A9EA8wgD% z(D;@!#Pz!Pnr@Hf_ewA{I~4HBaDL{~;>#vKClQeHAT3)jW@edub^Gu8EZ>xWTi#Wz z+~qSb%)j$h9*nQ=;3#0f&{KULXaXC_ZRfS$R!A5BbDOBkEy8Dbeh>Nb*zoXUnJ$*g-R(IszA}{7~p6mvKKxuU5Ei5j*KnV2< zON$HqL3oXZXPO-18Ay@%3&$2~6{`DW3gA-^hyu)lya+cZhcH8xD z@zB-zT?ByF{JQ<%N61h01B;$NtWp0LC$jjn!bhf4t*u**dfu5cwKHe_4CAO4#aHab z^0)fV^3n{keq#bepNJX%#w6H_e#m|T39SCJ;aiS=?fI=N`wS{0`l$MsiT+jpLS`mB zK$#~rL;}Ns(R&5IkW#hxD-UGM0Fq0Kj6-_}!< zezZ`w>@KN0JO@Ok{#B_hk7|8MJ`ABYpg?8cvHCh%Khj?89ppXie$!qIf?=^l^RsH- zVl)`=Du`F{5t0uWsH_XbgX|Xw0O=MCjE#+1e-TgFEtKGq4K>x^$#>I@3&KA-i#(S7 zuGHD9_+GR8_rXja)ReXum93T(d}O3r(8rCRv%z28IqH~|}S@-fwN`)xZTe0&ak z&?3|orH=iCKWREm0}908>XN(t&dnWxCnwa_*M(@0Q$gw|HQ8GaZ^z^9)S_Bk(R(u z= zulfKm_fsEhL4OrKllt4#-*`1y@ONUL^L(oRXXXDCAAyD>2H}2ieyNwXF<_zB40%d3 zLdR4MGSeS%{>IF$9E&OcONyh>FV>^`rWUI*xq&_Qc6l9;` zUvFYi?i02R~WwZh3pCAc_%k{1<4F2*;yfaT++I3rLju zV_M&N)z{`EWZZR!JU?_L|F}LJ&wk;8wDz;d(|#B&I-sn87c1;%hn|i1HtFXfHq#|2 z!}nirWPEIYSGu)5)z*{UPpvQQKVc*28-Mb!O?}}1-rkmuZP1S#oR0cn{;Zz__oxww z{QpV+s(vN^f>_HDD-VIBPW$jr7Py#e=IF~VKFjhq(pw%*Q@`*NYv=EE%^x-g_Fa4G z#xK%gf%pUAH)bp&n1$b%{9^o6zfJnnn(^DC_z802z|KEOfYcZc9`HxP|Lpolx&AFd zRNqW`8^Z>Dvp&{r%%}R3NBJpxW5TDzAd#Z<2pb!ae&$b0bKYb82mgK7)$(7;-;sSv z|F*$TSO9;!TNof$41ujrxBjSaZ23D{e^p9E;rs`O|M$>qVvT<`OMG{{`5l1hT8{YP zyTk82_aXZTm}XV?7s;Scxcsucu?Sz~{#Vb>1=ufGzmfPB1*n>RbnSjAj~fzSY-`)R zS@!py3xU7|*h}u_fcZylGV3Xq+jT59&E;VP*)!Q}hV+%Gm&nf#9%#(>?L-X?_}_U;IV;xkgb zyi2X`>y?;xAlZlfE1~2MQpY)<<)0V*D1Hz6V%r7(0o_N2Q6t=k{@YkUw5Lqx4TgoraMwn_?2-*1#iM z_~`ll01x>AqFkMWfC5LUdE_K&$-2>XP?E+iBC!in*bk@M&mnYP9h>%Wis=Hw3oY0OYR9*E+1o|-{_ zTtA5WL&m|7)S@Bq#bV89Nk57#IR5V5*&)TBaVK^|P62Z932Xabp_&+vYvpX8!cEV) z&BM#7Y4iqvcfZ>?efWLMHb)z(pT!1IIw7X|S==3NuKR2VFo10@7YM`B-0a4ar^OHO z@97VB}-JSL4GAnWJH_C4_$(wB4#A>q$XBEJ>JfFNw$cn}9SU~*2 zXfTD}YZD1-gN9I`Cpi`5Quy%TUz)*+l3^*CqXAJu3dHa|`~I5}q`-9|Cq;&6EBqT^|0` zn(G~5f6XI$2@65x6ZWcPoV>tX&H4M3+`DcY+d6xqz z0b?V>d7E!6Yu+wCGOFL4V*oILc>XYReavJ1NAZ1b{7^7Jk1lvRe}3J%^%RjD7=s9T z-fun6K)jV+L`D7Y7ZyH(?{WRga&7rsrMkQ{zx#)*Yq6cZJ)g(=&!az5-;k}wC;9ri z2I)WWKPTU%elkDI+QNbm6ym`S$bR-yL+d&iYU_gF%`7jsCjX?NQk^yaEe0Xz2Qfo~ zvyH5MWCrG`j4<`*wT)r0jp2j;BLVEEsc+1Q(MK+KsyR)4KL|jCkpulS`LS*#;6B}fX zOi@45)d$q{WimWeL!$XsH4!^1?-HAJz8Pq4sG$2?=zzZ4lMV5PIN<@AY>{7?nzi;b zG>;(T+*SZ4f;}fpH!W1MZ{s`kFzef;&i{HXO`yE*Suj`7E zlvnb5SwdTmOFicLu0=|Oz;OLUmyq`aA#_AiF{u7Z!zCJo*Mg3BG@GudI@sX@<`*8ok_}OLZC$drh4C|i`#W6RVK0P1WftHu6U+Mel zC;X1xyUqT^{~`S8E(br&Kc)Ok*`K&a2JSno06I5+0S@3AAi2qZ_TxX?d3a1K@T2pK zgNz2tP^OcyTt7pAEy$CTv6<9$@%{9Nye=8_2NHnr!SL`0G*bCM__+1|@HaGGcfH>o zK)=o{0zT#NOW`lW_4;Z-xaR)m?EZ+4?&~kXy1+@Z8R*M^GPs&;#5bn=)``jSG2u``cx=j^isuW&*+c8k9`6f1A<@yAF}l;->s}aCGo-k zrz!9658h`1h->ao*mPln-YJvcEJJ4mAHN zlA(4yD^vx#w?i*FK0*DNdVeMAUyy%Sj_UK;{9Hr-F8`nSWAeMB_~Rf~R1b>YC_g;e zl-hnOVd(INQ(k-)!EYt#v!p=MA07W2)-@}%ixDa-zW@nIZ(1Hg_!j%Sw=@)P^){v3 zdo$=4EHAmXSVGms?A_Xr1%MGDJ7Pcit2KXdqS{+4E=~?ke0>1^kH)d;zu5ynB|u?K z{4e#HIo8#m@7e!35e3btX`6>MwczVg;bwVOGiVp}}ihT)i!0pGpRbtQO`DfML9A56~-@5z;nB=Z+ zd?r`;bE4!5Ko;m{vB&PbYvk}a?vKwD_Jz=AME}2m{;z2-s>pfUH{O>tMMOFZ*IdrV}^(y$|=Hx`Cp(mXkPfv^O=`3uRhCq zB7MtB{1*>~x_{XBdvR4qqdYt#!194Q#W}Tr%J3)252U{W@t}|R@D9J>VQeSHRs}Ta z4;)4Wf+nE&;}-v(BjS%(;+DToWm|X$uK=9O_9I~xKhA!u&v4Ct)nAPC6O^ce-QShC z+B*?s5l25ib!X|&DSQ-<(dUH_AM~SZj)#B}h9CjLh`xo7fFR*Ly=?Ry;nyyRK>h`w zlRxMEZMtioKK)h6|HOu->srBJGzQ!+OFOO(XtRs&!9U}wALhbKQ_5dXB&+uPtML!l z(9hII&hIP#^*&y>FgQK;KP0si*)g~+fFFe6r%n#<-%E9+C;T-1>*P7q^3&=#yNo@O z53)P5nS6G8f3`cwYkkn2g`X@E!jNTO3^%4w(AypU1#8pcHMtpOU*nt%Wx9NU9@ag5 zy<89ElI+K7bW=_j&}4{;7*fE0k|`sF!Bm>0J& z!u;oLTDgd6haS3>*p_9eRe8Qdv6ueuqfIw-^ujQ{!11UrY*iG@TV$U^@r^OHA5nY@ z^Sd^G1JaD**HFLx6!;WV$Rr7ju=*V;KzRFYyT|T&ys>@q9|1MsRd_Bk0kz@6Wi!9f;)-@FF9AuxXvqL;G;(0>ty3`5{;le zzsHS91VSic5Qoq}bdfI09~JT{@yfe{>!JSf1oY>?hB5lX^p$1G!8$$*GJU9!4>tAp z?;uLo+xW?E??2b{zmUeQWxD%kSM6glr0G}WuT;1xIh`$_}FmMec&EzAK&-!TAM4o_uDZe)F4Ozb*)wd6f?N@+qo+F!j;?Nd%ZGIhb_wxJ3WNoSf;9zD*zByjM>_dH@Lynm*FJ5ETtGIMmBaeh+)+K2Ew>|-@MhlM zfkd7fXQj$Q{K-CqjSX3|9p7l>DNYgGMq4tJjr`5$^rhs@K&=0 zlR&fhZ+Sl2hr%9g)APaMo*q|>hCF=2%CF)-jiUd20rIW;XT`qc-atFB_)~1_{F!&o zoynaUdMB5AMeAb&1Velr@!{q_2+94O!`yqfBloJUSSZ+S+^IG(4clt^30DZjAiA^g zBfbyypw_J)JkO&OfA4LzC)5NRfdsaUex4(P$>`nEcKXAzzeqtuM`q;WbQW&Bij4unfkX_V| zwCO(#p9QD`QCWvq;RW>#{g@38QMAe4G7cJj0bybEFYc+W%PFts9dhfNwqLol)~L0R z@1%dy*w})8u*+y{!hh(=q*-DY%eN^d&9qQjQdJovaKb`FA$Mw6TYbWi|KCa zFQ(Q1$l)vEz1p|~PWiDo_=);oWrvx6>Ke!6b1%|gK2CoBn)<-5K14OUTqvAr4*c=q z{lz`PuQ!!$>S&-2+>XAH5vYsAgU=K?JQN_&xAzH#4hi|&_uezk0%c}%*;@8XXTM}0 z<(WGS z^6Q@PQ_HUpMZR3#HU%%O=r;L;ERwhiNbs-2e<}p$tAK34yCopKh-({Mk z_azdgU}<(gJ#S!JPi&$4#G~vMKHv1CQh9z!kFvPPcv9Km-pPs2$hhs#(ZA`#`(6EA z)o3sPQR8W}%rsgAjF)FN1^?9XpG$nh-)euf_4gIvs}#|@BYmkp`44MjBmf}aXT=6s zj7)$%cB~2aW+?K;!4ZTN{qa0PO9H|wv~=-@ve7%PvZs|b+->d#PxyQfz?H``jhI~kGC%iNhF&Ed+#8}zMX9;^ z<1=x}y%F*~I?6xLi35jV(JRjW?@Dz0G`5Dq*ja}EEKHrBdf{upP?zVfoHqWzLWV_X zV~kfPR-(UV@gWLtcm6Zvkw_cj*7QXCQ`m2mUXgsf75+d0B|>Xr4kYA~sE2tIGDw&N z^B=H>2hG9+2U>^joXd4|PVNKK(EN4xZOh$}$s8KSfPntJ*LSrx z|5|pK#Sg-{6Bz|fa_~B28UgPunq0+q04}Ahp z7?t|e0~TYNn~$Vj4JG{ zK=}9?*pM{=7wE|;{w9!Ow76U?&IuC-$^9q z0e&L;i1EWRXLUyPCm7mm_OIgmJ=0BoCd7YNE8+~E_G^Py|H<@A;+O6@%-OMD(C<(Y zsouvUSbUY@7nHtz58qV$1f^F*yg|*z7=GA@b^<_(bP8avSI_U_AJ^8eQWJ08w|gg6 zl%H?(8ySeQKaGAP<6QP91H{xpWm)GxGyN0(6VIYCWtdz+e`X;?{+*yoYKg`N8W)jI z?^k`NJ244A%aAfZ*Y2nP2JTVsB*bd?iTD~HUa}tHKiJ=sXvj~{K)LG}w`2TIJOn1h z^_71ylWgp~pc*u+k)j!FGp5dxUuJ@1!>Fh<5@9PISg?h;2ACvz| zJ>;p*XZ{z?DR5ZKjjhEC!%9^YVn5=r!91BWi`&IgvV&~%3dVXJ98--o&VH*0j?GM)+KY!-; zzW+P$SJlr|e{Hl&=ttFE%tTAn%>N+mUduyTMr{2lo{s`N7T*OzL;TMg`_J+RJj4=& zL!Z^9`K4tRBr*fWgPUy+WzbKtz8yeiZnhJWNAdVRe9@@nNA`uRHAsr;1Ix3oF8>d+ zjKAim$;O}dJ=`Dg#e4!4KYDY1%3tEY{Jhi%ek&4mYo0?lOLn~ZC)8dTe2C+po}<0+ zyv9*OT$YC(#|I!Ow@Ur)uIxnf*M*<0aI5Zkp1qF3>-wD+WP~~t9{Mb|w(Z_KIoZ~} zB~5Zo#17>;e8iCmN*2=*<_{ASR3N3iZo{K$`*t#s1(5YvQw~ zcwQ!Wa8Nvi#B1=RR5CuCZNty1{`KI)7bl)h#D8OIz5zP&k0-m1#nFSQap-yTWBk6- z9Ux(iKd#CbU=&8td%SfrTcA88{ckM4QJO{xE|>khNHq$NZM&7UpNpbA_Kat`{C6|3mT6k%yFIAN`(PyfV97xVYtd zouBYu+j_PQD}GZ7C=hI=7W;#~_2^ie9vvTl;PBxG4nMN4G3LcPFO5C0_#W0dDmZw) zE=qh30A}ZLritrIw8HsgA3XKc2f9BJASSK;aO;+bp-&_3X`a)#5O{mNez<59`5rpu z3m3a^DC)5{`Yi)vT*Wr<$egCeX+P*c^tS-|&?>i$tXJG)j2$2NALGZGV_CS9^Y7do z**Tn8Cuei^J+9GI3eMfo34h^BEDhg(DSV0iZN=3}L)v%>GbkIv(m1NRyu3_-U}sOd z{FaG{&m!uuUnMusoLO4pALYmSlwCsqZg=|kZm+WOAN$Y#!N4#2D4=ns|0L{@%F(UU zx`8dn(EqT9-bFz?H&6In3FJ`nGg7ZH08_?N6=HyT%Sc|MKO;ZjSH^l(naAm;YxHX+ z07dx4JVgo7JODJMze$0U{?>D#_>t$6{;_kUar0*N2T4tRJ~0psn1OU#CK?=$Ux8j-}s9Eo^jRKzCa(N_`XgxOgB!eq1F;Pz|FrzKz9SY@gF!Kwe4n>IdmMhWI)C$S{_=%J z2eDD3UGbZ*l*FG4g}Y6E^t#|PV)8Ef2z(b0TBWw8KTfi*Px>3t9hor3_+9l6`oDA9 zOQcn{Ca>hAR2KFq`(+t^skiWB_*d@?zYT$j_1uAi6w%ib=`-&BQr9d0kNVP(*B(#S zb(MuzU0C1`$e-BbcTvBUCi50rkK zST72GnR4q`m#9{p`zcaE;2KeU4*Gi#vLCh(cL6+BKOM=#gJOh0R|h+FfAFwv--kAX z%*$QUFAg+OfK=#9hvjEi;XvF#Y0RQ1WZw*7;UqR6xA-23F_sgu%;7scG7)06i9Iqv%NYp*}U z=unM>`l0Un`IjodfaeDtp6PT)&eVBA^5ejfDSooa5Cetu!obHqZ*2{_@AAN>;9T?S zf^&YhFvNHhU(wpye%oYgZ|~vt8XpvdA{=sIN>LM)~VvP6jZPZVL)~coX8Vtf>)hW<+`)%Xn7T+BP6KYjIaqMV#zQFZY^BW@luDACW zghudr=#P5IQ$~Dd^U0QJDM7rtJ)J!__;RKz*fyBSKo8O4HzpweaHM&_1tR~`wf%kI zAJ^aqQT#Qxt`d`buiDoS{iFno!(K3eBw-DN=)a)(L3Pbo12yFjP&_ZO;nCLiP6iSE zI5~f=vb>Z}zCMGA4l#&+487g>uvV$fpP{!RA^0Q8XS{h3&Qw=`-fMkvasJ=@YGLVx zrNyVdhQ6CR)tVl-e;o2jw;?~OiHDp5O#C_Lm;Ook$yQz#ABujkfQ>X#ni(Je%f$?R zVK${wpO_#znQgQ67iBlYXcpQwO)uo5>Wz7=9<86MM}&!#ORb+&X8$_!Cm-PIB2e_b z(xLG;vu`dfedqP1?6C5O0BEA_FT|I!9@DLV?Sy&ir|=Uo2Jr^_iT-7bf#tnzFw(!k zd+@=zZ?Rwa53FEyzbTFu+870=Rhly0{sbjlzL%hQe1yR1#tpz z;l`DKyqvTg79l;l-zO-aw)5UG3_X6QKE9*u^8+5WfT7>$0mlxT|1zTQLUkTP6#C}U z88+0GUZ#`V5WvD_yj#YC{-mq;1HIdZLw3)ip%^&o>L*6}WkM_}KNabh8^0$Om3et9 z$97TT4*-a}lYfUpxrM2UH*g+xwgUYtHb<$E#P=M$3;I%c3@bPI!xMkl&G}>>0Rn&Q zk@Z_*8x&7aTewV&1>vW`dHS!ieheU}uOFUC&*c;d;WyyJcc5?G(Ztrm{QTnd>Az>C z{Joy~BKgH0Brcm8<2L>=_M_GKelAxioJL_oKI{3qMBg?~ntxsb;ccF{pL|ikPZzH; zPs{yNAV$WGbkvH%8!6A^8G5N07D!&|r^6Tcg?pW8#QN<69YEvZd}vM640F(%D^R6C z`?YlNf4KS{|ZAI0y8q4d33l$D)O`%c4usW1FV`lpT&NKgI@o-^{s zSl}ost(q^qP~H&gjp;Y?FVD@r{>Ft>{YLezin(^;1Ka)V%^}Axz(EbZ4%A@}{H;7W ziI1Lz*+04&f8e7^=e6w{{}KB}^^+-|tl4WmA^j*|gai=P!n^QaX#ud$$_GUK{WPaOKkofqG>;t{+%Yed!s)GFgWtlVyb3O-AtXI_!`SW zDI6-qdA^!Q_sl;&yZp!f%P3^xZQ!Tmmk1%c^&|ct2$c9jzkT;aYa0Nk!y$2Fi8<`2>qlM{b~&Dru1lM@O!x8fz6TLR3BC_Zh< z@V}x7DG4g@n``2a=n zyOozEK7@Q2%9Sm?pYnFyL)Hd&MsLOA-pOxwD3`*)<)t!vxdqWu+0@qmlQGyyrGCtNn(ipL4<753JjS*kF+w|-BmDSzQFZvHG zCu)zS8-cTM3()o)>5CP92YSwK&)vM6(ZN5U^`}RiM-I5>Q~$5SI`wMU6moF|aE>WXF_#JHURvZ}k z&*+d7Fn)gXuJZ%Uk5n{KVW|8^*PuGGk5nHQQEf@8ir)#^o8rUt*AadMLI8bYcvce~ zHu}K@o;!K={yb?zl%s%VPad9v%$`^PiPbvk4{85j>5fk?D zCi?rL_>{Qe|1Ddm=s%OSse1ze@kiiq&~6{$Q+T0wHm+9zC9eu{kgF!a_gIKFzFkN2 zngk`0+4xqoS8zk{!XFR+ZOxA;0xKWI2Y^4D{I5pw0p(049mfikLX>B^UzRestN<;= zXOSPmDcnE6%h1zoJpXDun_blZz^~d{r`uX@1D}P#Z0?Zmu=};*`x6uI7bm{>@1O_t zUyRE>;)gTC_jCJ~lkX;z@Ame-o6P-loAX~XzsLuEa(>YV^NaUWU38uOA`Ev(9o}v^ zVf%xjV@t`8{{R+0BmUu&yTfEE0K3EROI8m0fx=f}Vmv%q-YXZ2db{{^;cwRe^I7bJ zeF?bL9^Ds$kseF^Ig{T&%hhmZwmA5I@Vu!RYMZqVPH-pK_u@~c{YU%JU+@r9 zMWEENb4>MX%>APP`>;B9>L>93riOy~FRZ|h7pF1{_(DAXGbG}8T>Q}jEDc`vr&#~8 zP~l(9zw(zESn|_I;lz$eVgJLEw2_~WRrrILXYsqZSQN&S$rPy1BK6C0$Ta$#=7;zm zordGde|HiFnrLEGIPlnLK_K%j~K=S>AHoP-58a%HU-?=j0*85u>Zw(usM|Ec=<@gAR| zy0%Iv_2GZ{QBaImJhdIdxJy9Uvhi{w#Hc#0DQdWz71gl;ahZ8{`YQytI5lQ~^Pw5L)v5>jd`q|XxY=M3RuWNyOi8*|8<{g&g`($`-e`P}b~+{s;JGSG8C_%6upKJLOm z>O51F0AUsJXrr(7`~nCo56X7+c-E1wzk0m00F)m*?fT;)AQV5w+Nx&9$DbxTNcy=> z&e~(Vap=N^AzEezm4s|wR-yQJqJJb=9??xwPec3>oiBTg0)E0@BmW6W7Q@8Q)_;%V zfR_K_S?At7OzZdJe*EJHIX?Y24CPM<^a*r+v#($QT0B!c9(1RNQ+uA-(~^JrsKFoN z*9!P4@;?&4p71*b_ve(pee=z`w+9YCT3#y4MIijixNkst7MWO#BJ@tayNnJ~0=S~X z?{-hL-+c4L2KWQI*EvqWPfoxgs*t4efvCvH32H?Qo2M(ncRhX?F0(RVPZ{!sY$!#& zk$=U;PV?&wdFCe{&975~lNwfHBCTk4zf zN0xwO?5qXPG5K4XAo2`zc-&r@&8(&^Nc= zE-M#FuKR+uB`GowG`~jSk3_1Tj@b<1$whV>jRlpzEQ&b@SlNRSw*Ei+=P^j?2!5A!6z+zS_tJ@`*sujP5%3}`@M2F z{J`)bL+kfic+f73&!~@(#g~eUiFNr8dR}bEb7fm7UikD= z5D3#H&I56{x9`o*!Fj~_?fnerZ<$W4YfRlS*<$)d4#Hh~ex9rzpN$#s;t$r|fAfhJ z0zd#jC&%Egs&8ougyxR`**zZYN9y;cSUK5#bUpT-3r|2nn@0c)uGt@N{xZho)&0Q> z|5B;0-T$%28mU*mdVJ7vUvEwih=%C4%mMX3FQUE)UGX1!3jJ67FS-FMf*t9H(h!@$ zup|4Q2tf#|OJ`e2yp~h!OOc=4pVn`;-v|b`POaK`zVaFOgha^9eb&zJQQ}59T(CI4 zUt0iPgfqhAI6rF|^WqCoFe%f0x3b^=c{cm1)Vq1v*Bk@>MgIKtmY~b|IXm^2ataVd zo^e-7`?NW<_&^chYe@gsDH#lXM3;q2L=4z2ix71U(m221WU);BhxLv2_-y3honQJ7 z8a`6!v2oj{_@DF}aLKUd&%ggw{#Vg{6mb3l$`&ojevV&3a$T-0EPx-PprYO0M+DTw zbOYZArW!tC#gHSC3RZQ=}&Vg;M*63FXwmpMbN;&}nrcl9gK*uZyZt6E9+ zRvkO8FY|iGZX`spX!#+Uqjz$-cRD?uAEHe^-lhgI5|2CiKKJ(?|9!t1(^CEc^e@)X z<}c}glCRZ3^{sNhcK64alo?|kZ2fbfq-*kTI0@_{-oUDtXyyE#*sDgF-!CyQ+(Gow z{W~@wRv-oHS@c`-cPJ9Zm(gzza(xX;P*eShO}~s$|FAJ$=t0lDPD~8>d-eXYjTv88 zUP@CFQ~%kDS?(S^f+`jDpY=S_qqBRCi@x^oo0}i7>MKv0|00=Ef5h#NHz_{Y>RX>X z)|vg$i}NocA45(n+hK2%---VS=+6b8y+?U^{2y9BXfF(dIO%}s8~dC45+Bt1)qXc& za6iREz~5w9={>9b-F2CCsoRg8KnI5ZL)0ttC!U2o>iLzv5=`jd?6=-{400GMoFRG@ z^o~48*~4X-S7Ys|>th>FZR*hTBR_&#t{XQ6_=5*9%V)?9Jp6+jz`w)L1%fn zQPe60ot4|%Mp3KO>{Cos9)l^Gg4|xtT796GWxm4SE&c`tIjWx)%)F}pU#s_5_ity1 zg6y{2k9zdyEzDkF{2xEy{OiC^8M$wG^-hjy+}?+Jc_mibCU<$>9fS|nKX-l3OQ5{) zdg+yyUOD{--_`o;iays_{JDp33IzCJhR(eiV2fb-@sp!n^OKKCM3Tk z!MMK~-2*ZZ;LPkS3M$X zczCqg^%(%Sg-ko_L(;7a?om*DiJW6t-=^L{pQicHqpF;I6qKxih080r98?#c`A;t? z{vuiCk+#}-OjZ)AkR2*MgPtys$>`ex(=5mUb_P{m@<}g_vOpz2Rlh(EG~qWN<}aSP z-rQ}Ngn@cdzU($6AFlPUSp5^|_v-jv>!146N5No1&f$!_U2R$e<>>-=(^+Lp<5DZUD} ze-H9q8r=2X`1nM1ehe7^Ba(mLjzoctHn(u(_^fY6Ku}pZJta0`xT2iHwcJ-lWyCe9 zfE)EQbpDTjx$F-s^yQD z%B7LJ$s;eFQhX%hqc)%1p??F_!ZZAQ@DpQt#uo5%LmtlDbYkxIzZkr5&HPCJGCCHb#r$fikm zXUChJ1;|Ym3(q3hpdqbq+0QKmh}G+(NW96#g^kTsq~8i3gF~o*vWqVRxrGH|UMqi_ z8wU6Ng59U&FKaSbc;;7?dFMvZEXe~Y?T0Q4l7E%j`Sa%9dr$V~`coL_o&6)8OEUDl ze@Ue#Z%w6cy>;^WRO*o^|9Kq(Amaa*Y+e?|_(wi$o%r`bzNtUPGax@Abg09jwD67W zj%_z(1KRgd1cCa_wd5WmqEKvd=*k$*Rp4WS=LIN$ls8M9v;fl-83;Z+Ib@9KWnUyosUBGnT0XJdXezKO)# zyuyRzpHP0-c8O0eWGW&I_%gi1+|0sv8sd)=zXkE$dCKmuTDR^T{jzkT_&*jX>yx`P z4hfH}h0qsrIa1$&p-^98E5>~A)2{s67b@^K{QrjDOF{e;@hi2GRzMthO7zJrKC#+f z&g36A5LkKNh3A=He`|~SUr_+e;e)0=M8%(k53;CGO>U3c%e5e17$FzH!awMjU2FSi zh2HEFWJvv$0N6yWm}{1P`gr=|w|yFVa`;o?wFiU;FTFA+nqz(;aN-BhSD-**E*Rf> z{;1XeRAAlCF=5M`;d-ZcVZ3u~8-J+>oG0?n3`CkKYt{TS^5Yv^^E_gsDR&@W#elpje&wacnhrU%y0)AgPd-lrm+5hb#_=8&? zXiv1Cg~HtW_%1Y1k(_5g8W0;CfR!2`A9xz+rrOMY^YOn4UWL+xZ#%c2bs!eLZTRzc zN)TIqLIM9c@SqI5v)lssn)sidpZNV20>D0Ud_E>37;_ald(tdK)a~hZ+-+v^!4}OMExL^nG8Dmt&hwA)K=v!@j|x!H#=`K$c?xh`;)U~ly(a>7<)d8us>kvW{385?jkDx4 zK~p-`ut%f>eq5=>XUB4*Pn{x=Vouk|XPQ#%MNW#8wEv9uYMigcYB;^|{2DVC`OEm_v0-uF&>(mN@`v~fv?JU%WU;ZITCd30)Bq9h4qxD)%LIWXgJ8U{ ze~;R}xZFkkOMYU<1;T=g#~&I~&-Q}sYxrMFOST^W5(HyQ} zc`3zNZtAcCcenHWWekYjKNQANm}@qf^F-V@g96_&Oji8m_=P^QDv-0t?wB3*F12(Qv1QHMKq0& z3!vGA_j~zxYx!fX$B8FVeZoI~DL>x)2m|-8y@pQ;JZtK|rN6lkEslEMdO!g5$X z{RbKG7xZ6+zm18#nf@CMf#kdDH-_XhnkFjoveuGGAM`1Kf>E3}66Hgq0mVx%t!84WA848$L-wv{&oMPr|$ zA6RWG_xmkI-`Zs#eOGw68LzTl<)73y_4Z;;{jAYyoLA{tfssQtJvcw5+0KZvaGocqxjbi2|_g2ucJWgw%(HAj~I7<^42q@ z-ZttD#3_zAU^EUTNk5c>9B^yqKO}q^tDD+I_Wm~GhvWg_>9%(^FZvS;x@d2hsCXTL>$Gtr?WcwN16!+}{nN90 zOTIvVzB&-xcvAfRR+Imx0IbS?*vD#rx0a9WPr!f@5Sg}c7;= z``xAwi80f>MJ5RR(P@Ta@0wp8zl##~`G(GhJ+bw-OMa~+E}`GQKJ`ZFKt=d`JIOap zbvsc)#JAF}ueG(N{xP;Jbc2!p9fbT+VSpn2JM#Y!UZLt88>WqaH9e)+$K+D$^04tQ zlV3)EFj$EY!!MJV#(ad&a(YLY>|>yH`X~TimlA!_S*|GI$x7!di~tMT;E8x*kJjJK zq1p6-V$!_=Im*U8S-rSW?SL{r?HQnd{8pO2^Y!%ueR6ktQ$AA{aQFf+S@@ERKSF*; z9$Wrlqr3X@vFxt??S?<8eo2bwGBc9=EA?Ku>_q^8;!m7^Gdzd|d@u~7-{Wx>00qug z_Ya4K(b4h4SNG2@HZ^50Vt@PDHp>rOt*=J`ZMJ&-p!)gsJZ!7yclIv$9O^ZZU4=LU zAoj`wzyQVj=8kt>cS3-N1m6k$gDR-`eeoUGgQA}dpOk_`9nYltlMTl_t}#EiQTCs% zAWCQD&;+*+=Mu4=nm@6?i%WO8{I2F*it2X(-0H74c%VYo;W@&Ib6Ld?cnlx#D(_U+ zNv)t)G8w?8D7-}bowJ51u=o!ym+MH@8Z84V&VjVHnOl+AR) zp5J6A&+qu3)GtUN3|)K?tYJH}qOFMjrG@Lj-$B!_Sgpmz^zN}1X}8kPv5%A3tt*N7 zu@mSo*Wx?MkF@yB)&2qr7T~Q-4NbRl;|kA#|1A7n?}gsKLj|<{Wy zG)KFGJ%^HwM9B2@?Knw%ZHCtZK{~t?|496YhiR0{S$9?AZ*cEO{yr=F9Q%;|o8y$X z_fy{aO_4Yn`H>Rr#UDn@fToPgu8k+fAAAJ}F15~^|5*J$7i`R<3?fk$$H7L>~mrh&% zXpt8#M)GH6Bkj}pNp*5MD)NDab$AFTvf7Je)E}TW^}@e+KN{h+FYNyS`_OyBTkWqy z{j}cVfArq&qX1#w+nLN4xWDPt^yF3l--q|Zv2mM!N`s=1TjIAq(!ZPd#=}HuZH7cs zqJP*2tH>4@@@o@$bvqBYx1|{f=iiilTbmrJ5MT2(?muo7USSag2}7?d9f1p7BS8^; z#3V;Ud>!Cw5K2FZ2+&`cGW-hZ5@fBtTkaqV5c|=5oR1wc9rR+2BZm)vp7^uFlfQRT z`UZ8rv!neCX8*kxS)ceXcN2QW%)9(PjRp2bcE*o*Kn#eWmOsQ$$e zJ^yUIM1`@%6gbZI;nN$ucp=*rZ+MucLwFofC9J+ThF&ceA3%7$C|WSxSg|L%!7g+B zU(x_G4aR>PhT?e(VZn{H;S~J?QmOaGC*C`J_?M~nH!QwN2?U6M-qEc)iMjqze@Jm3 zv|nQ2zcBnciy!gHtQn^OJcVnzjxsu8oY(m_Pz}m2)3uW{|3nGbAA!)!{;)5=zop-t zCx@zTe<-RHvsFfnAK>3ZKX16q7!xKlH(P-}8~V;|XajFV`B89#n0OGJ$9{$PT<7OQ z)u567KyM-c4SLjH5}UqE%4K(O2kPY=L3dCVgZ<{k+5bWS?SGlQI9oISQJhHUa$}PT z4C4FO;LE{*({=npyh}Nt;(yh2Eo~|I=HI71W;)kO5!=)@MpyG)7WpC#Uw#??pXdVw zG_r4$U%@wY_mpoS(266-&r9w^_B#Ku?C13S0Zbc78J<SSzmB z3xAz(7q#En{K)kvz)WC-j(OGb#cc6K;%i8tLNo3Q!=8`CX5UH3b_e=kh z*0%JPN84{yd@1Y;kM;4~xie>mh`M0N!7uI{EsrX|EzbD=tia2pOC(>w$JBn2^dLka z^NZaN2cX8$$n*3+1CyS{dKWw`2FUso_8!!-yT4BZ`wL#i{G-atYG*z}FF|}(gk5UE zVb4Y5hLS_-1pbFrkI*tNv95){^(-{BicR!mC!5d}a$O#Vu|S4V<9D_)kpk-t15J z_4oGQT;lvDe~T!&)@9y9eky`k_N$ZcxYj8F<#B$K?~?zCJQT2=@C3dk+E}Qj7w#S) zJi+GQ@=GEEgj-?wlwSg!`oSgab^71JKb(ID5AgcSRNf>2fzuei?$Y`i8-Gjc0ror4 z3GNRQpZwgW_?=X&;RNU+R0@8#^Lb#9Tlk|eOpg}-j zcX@Fey2K{>b8aAm)(dRt7B08G=f9`=R;g5O6c&s2MyadpFweK}K>xh`ckXx1zi0X5 z)?cSn^?%L}NxExWHv1f>_=q$O`|}X<1z>Kq$7LMQj%c%a2_3vpNoP_(NSYJ_WQN2D74{%KaH~d5Kg{%0X zqb~##YPigMM_+s;@?V;LjSG56Ib{_5g4zi;cDg)aSUIO}`Y z`5N9~o_}U`?jh+9(tyw}qW)bjK2-j%p@RAYeAN`$8TdQ-?eG9W%xE}ve`6Ly(f|s< z{H)feaAA9Ro3gJebg?E9A>v>U)5sD^Nc_=$Y*q>)r4!ugn`qz?Qh^>y`Md_hmNKdYJu=h^cXZTJ+g$A$ivo!D%9dCq# zh-Psp{>BK$yF73nJ-4FqFRQXpoxX5oEE0&i(S41JSbvKYE&NiQQ~wqJ6bY7*2y5AT zEFOn`YToFs(KxFsGxE=p_g!N<+p+(4-qX_4H!S&7;TmspnejsOd$D2}9U0kTAecFq^ zIzGVs=wVr9*g+v0i8db+xj-+q=Fj_tPi>!Z}0R_zG<+5eV1>1>iPdW zG(IQ^qxtuV&{BJK5J-(*SbFi|>hT)}(NpqAuTB$CxC%`~)5P&*j^CU6yxagWqn~Sz zr#{q8Hv?gU&y+;p0T)2Yz{6hT_nPK!|EM}>j(lcV@y*g-=T98@+DlGN;rvl>pXu2) zKNj2viOqiieg}OJTqhlw7xI+sxNthbhu0IsXtn0QI}C<``bB*%8~nsdSTO^!iuP=& zH?W!9_R%Kj6X!TIpB`|>6^_=JDB`d*fw0K5zyp~(I@f-^Vld5vY^dEFhu zyW&YIw>bR@<~=(4)O?2*=~wE{N$_T@QRQuNA=kf_{@3mA^IQ5yue187tq*xro|#`M zGWxvt@88GxbomeLyy5yAcHI*&{2osiR{bl@I3dE)f%EJy(_r|{Pl4i>9$W9}{MU?6 z@&pYoeSh#ae2@?U`-yuim7WVF<4RvcKboBUZF7OEgLgaR0XTqY;H8m*K16u-PBwy+ zNx?V&2l*W@$$qKF_b5cR}sy^i9>Aaqr+| z(}B&nk2t7wVEW4z?<^f2g}oKDK5YKxlZV2U#Onip4em!#>`t^M(I=C9jsBqeFydPv z0APTMuL!vRXbJEK;c<2S0Q`ESg#W`0fWNqOMD+&;nE%G~jpT1oT|xrb6YBb_Iu|Ft z8v2oKB;o@;?c(|#D~H*mh!nEI){prwdV5*#q{&!rVrOSR{!{%95Vv7C)6zixt?7sS z?OZbX;%C{dz6slwR_yN0!p5*Y2Nq>lNsa`bMB1Um?651{Sk; zrB~J-?-ATn0<)VDf>e%4etFXhcKQVhIh|M$PyQ44UhO{@NICsA%C!RIiI9(-Djga- zeD}!6=-ri03m5UMdun|Sd1@M}1 z1qeT}v4V_MeS!v;A4YwZ%mIzRa23c*55oGE@=Ofy`k3|x=zmXESV{}lb0-x9Y-osCsc=0yPTf6KpRj#AeTXl>aBzNq2T?F&8*up1Ffl(%W? zK>DXUkzWw%n+)xni?iZS=$=RowO2--hOFP{c%e6Uhx`HNmhbHqygG6?O}+$MWZ+xA zh!>!Lw`M=*4K+1wgkBWC9I0@HncNTc{llNZcWrkk`Oo=ri&t0APjjhst1NWaK=;G@ zdA=D|4?|SqzlJXb^(_N`P9T@f#o2`;rip4{?8R2ggt08{htiu|I8G;SYdt{A+ry>e7dO|?VrUy@MuI= zlXw~GR}e=wpW9x1!2Mpa2>Rg9GOysjY;P?Gx7~u5=$6|8e_N@%^3+pL{aef5 z!GPLf0aQCmhp>;qk656cXOqS#un$)E1J6@Q!>d_z)E^{?QPo9KitQy=+*@eA=~ojm?*r3Q)${?GlP-tW+7f8$Q#!>Y=_Udh#RE4?gZ29*3BBF~HU`q_+) z^PKoc<9Eibr1wM=*@UW`njUiXt%b5a_`uke8q+Qq?tFwCF<i|b!?SIk}KzjX1biOD;3lJ*mN zZlf+P+xUMbj{kQ3SlX&3V=Cm1+R3&Zf8Cy8PNF`D1+t&Vbz(xDM^Bo*JNj3>op=9y zrDk%G0jlaJf){mS2mX{ybk0u*)pIMx<<)`zXe_r#e z?d|mP_PKXYCuh&<0Yc&a;+8G1`HB|c*zn}8W)D6n_%Rq+p7v<$2&)5yho0=c! z`F@qET|*A@Gd;Xlzwc92?~nYHeeJ}{i@J$pSl6eshsS8w{d7;`K^-tGE}We^`{X6b ztugVvH{SS`R)5vr{HFS!vS?JPmxl%LHhyK-;|U}QtMpXy^Cr{$E>vrRRqW+u`ECf7Pa@ZT+5}?Q#pO_nCidMJW(9gh9=mltov>wlfej`{CZy8&Iq?k=m-Smr*yOR-L`(kmalwSJ3c6Fl^L`(^7Ny0W4x$O8V{+z(U%^$ndP8kcWk*C*Spe#3qn z_Re4JZa*8&U+Oum(+@7#`E3Plzdx&W^EUsnpyN?nKKW$mUAhCal}vV~>W_U@9+vu8 zuV(XC&AM!M{BzcL)n6{LeuC!tH2nt^r~0qNOFU{^JOvZd!|DiK9O!HQSD)4T)xrJk z$p<%Yejv&E6-^uL`9MordUELbODePQsohw;s?8sC{>j|G`n^d<6w~@`u(qpS*IUqe)R{h z+4^ZaKcM@YhIN0F)=xH+-oNq6h~|izCKU?d{FI)p_sBiZ=>R=Rs9X?=oFHQ@TXf0b@pgqXF6_a zkFw5*A-q$hfqiZ|Mm6V*ny*i{eK)2q_q;G=}~ms`Ehy(R2e2M}Def3wfUFv(8G zbpW(|?WdJ+5hwl6lP8p(*?l{A8P2~oD&<#y&!#C|wb8aOOped!?7KZ()XvZK8uk5| z|Ii&OfAq4_H78U9HS-AX;rUTA9hyK`(D6?;?=-*4!ku;XZw+uI>|5$VSl=P8%KYo; z8*}$Os`cp_|Ehkxy?AoR&M)W$;sbKObdTQStBUK$wt8~E4qE-uJtIp+S6CicoL8P! zOa7|t&w6?PYv10N0(SqLnOp^R^AOY~8`xc4WU*j|PIR~BSE-x`=^Lr4SzfuatMz}f zZ~B3{u!8k^p`aopf4J_ckKz8mkZxzUw7%7@pKJVR-00k0JNy07><3i87}Hf18E1uF zeEyDhKk@WM+dQt1Rh`st_3U3g{kLHAM^(MJ60Xsxidw&|s;dNvC>P|ON>+cLK8N~i zf-V=&Zp5_a9VtH+Z%-Gt@|Avv_HB1iUAN<}`sv=m8&<3aq~6Uh8(w7pOdq*0>GY@O+o|qvF@2I>YIWbJ z>iXx4f2Hm3n9$81R)Onw_@tYz9`{S{sgUx}=8L^Hr>Cg-gil#nqL#|2^w@#u=^G)&)xK-a1IA z|Maf-^yas3zM0iu?VGSv{SW%7eOf|L)j`+{_s?l3cc}rY{)LX+-yr2QwYMIi-=Wz5 zdMw|zw)PbYy8c_~w|b9l$ogG>?7H+-^<Co>C_;%GRnCD_=7>4Z`Y5`oOH#&q@B} zVyC#A^k3i9`30N*+32#XkKq6xXwdcLW9#Z;m`8UShk}|I#+UUp3mQzMqt8GA`Um49 zT88+FeZW2rjDtR4AFvPD2Uh_5h<(I9x&rV4KDc$nzl0C)!L1|nXZQdg;DajwAK(Lg za0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;Dajw zAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV z;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0 zgIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC z{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4 zd~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lg za0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;Dajw zAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV z;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0 zgIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC z{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4 zd~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lg za0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;Dajw zAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV z;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0 zgIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC z{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4 zd~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lg za0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;Dajw zAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV z;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0 zgIh=Z2lxOV;DajwAK(Lga0TE4d~oZC{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oZC z{{SE0gIh=Z2lxOV;DajwAK(Lga0TE4d~oadv*17U2`GR9|8EsYj)uj?LV8tSj*N_t zjOg9tLm_^xakX(Rq~9JtQBu(NdHT@E$3}(~Uud_lwJrbgvEx?W)wcfWJyjS#6dz89 z3S){}cFUiaXYjTCji+O2dMJJ37w(*xP<&D8i+az?%j07sW4F~`wH+A>`D6QrWyh_4 zSKIASA1goBC&r6Ix2KO4hHgtAFUI=j+YcQ-K3-IL?dLCr`seK(==brD-KL+_&)S>U zcjQRAw=dQ=&!6i%tOi^C71C0%Q!JS{F{I^6r&7-1>CF6D(NntV=Lw??_5~Cu;UvlLr;H) zim{K=(<&ZLjKKWGpj+lZ2i{CSI+pF z$D7T2KACN=uhcSo&EN75vAv;gYDhyzT>8bJ*6V)=Swfag{jJsQcGVs!6^d2-k8fJ| zldUtMKGV~Zq+VA&oA0ZHy|#{Z`&vuU*1qBopJ{ftEOeVK%fH{UBnz#O-fK1+jn+o1 z(P%cU4tZQ(H1-DD|EVg`4EuXOY-@Xq``gHlzP)WIf3O2)TS}$v_Ck`p-)yzdpI<+J zzTJxTQ@Jt3{rz?Gx#ym{eED)--rqEzeRgea?cBL@XU_as<%RZZ?+RJ{m9up%6k+un zr0=}adRXxTD`+FO(e!xuOt-t$SS%I0-M7E1cyDKCP-ClaY>#c!tS{wp6I8lRXK_{U zvVB#LaZA)+Z2t$6TZ1l?Y322{x3lir?3$j-l|x}UNkaY);()OH8&RwHsxQj3t**ZQ z=+H~lX+E5EH7zZ*wzpsXog}$s!essT%B3vp!V}xu>HwzSsO{*K;tEeZl%<=72kIbd z|5!MVnL<`S3lD|-Pn;^1t{pDF`EN?Ij=7NKSNTav^$R=Ee$sRy>AN&e+o^=XA&izvMK za`)EaQ1`9Bu!#1Y_t}^`N#2ROJM(!afAyd{nv({Cq&i^h35}(AAZ)sV1-JPt+Wgvssv&QB4MM;c5E$Fux05rRnnO zYN0qYNKclnLwE9csnjWrPSsm^yjhyDrdDb(-lUjDyL9g)p!jPuuaQs4YGLh z>1wsA@@!UN(Mn~dRPZWM-!Zy$HZ-&q5RIRpZ z+0_v3f6_XV&2N*Wu)12UDtq33+y9q_2m3D+m#hT}S$SqlL-jJftQw*A@%UNKUAV6n zI`5T!Y*3?+Nbt})Nx2mCq(4M5RdZvBV z%<*b0*!owtLC9Y=Q`#yP3x&A3X+1wbr&dJ0Eq}3iWh$F4Ee;iug;C9%u8xHbjJD;9 z9fIcdP=K;mCy$qgj!&$I_@+tOv6rBy-gAAk{-nOA;N4F zh~q=_pPijkI2ZeOXzJ>!<~@0TSdAgmRYPUfidP4SJ5X;3f`sGOu205qvsd|JSuy@~ z-#&(yXkUVL8<;p*M{8_&u@B|)-r%KNC>%RBJUl*r;>5~Ir_=9mZQZ)HySulyzkhJh z>zTdpbXHbQoERS;9zJ%gQ0Vu2y@P}O{k^^2-CMV|w&ah@%*-q=cRIg2pUzl|9(t%_ zVR?CG#yW(hTk;^T?CE^S9`kD+yR>OxDK{@+GHsJ;l@^2uw$Ud12AW30JPa8{P2mfL zmtHb7+uY11U@yI-O*-l+XU}$|>Z6L4%PXzYig0X0Lh)p!T8;m!kH-FJbJs9`4ac`s z8vCsa&%Chq%nQehHr}T+4r{BAOirptjat0^oA*EXYbSsEg<7pXYvuhPL)M(wn*V)S hA0{&2pa2S>01BW03ZMWApa2S>01BW03jC}o@ZS+Jp4R{X literal 0 HcmV?d00001 diff --git a/30_day/nihongo/jpn16v00.fnt b/30_day/nihongo/jpn16v00.fnt new file mode 100644 index 0000000000000000000000000000000000000000..cd7387ab0020c48601dfdd25c1d59d769fea5b44 GIT binary patch literal 58084 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 literal 0 HcmV?d00001 diff --git a/30_day/nihongo/nihongo.fnt b/30_day/nihongo/nihongo.fnt new file mode 100644 index 0000000000000000000000000000000000000000..4faa31d9f01099ff14153f17f7a8cfb891e15ab9 GIT binary patch literal 58009 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 C0E|lj literal 0 HcmV?d00001 diff --git a/30_day/nihongo/nihongo.org b/30_day/nihongo/nihongo.org new file mode 100644 index 0000000000000000000000000000000000000000..e312bf5b7e4044adcff849980606951ba48bdd9a GIT binary patch literal 145472 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
      -iO|P(5qiOQDo0inOQi^a4J({pw zJ+{NL+54!ZW4A`h>4}Ha_=k-Inn7E^tevdW%-m*nx|5tv`X9`)u)0Ajtki>HJt-_L z7B`w7Zm@yo)iy_ug`*Lhk0>>=%U>#Hb><6()}rFLN40U2Rl{vw4EN$`Bat@P`Qjw3 zrwnV}6A0I74$Lo44oYT+!D1lS}2jIS)iD9I9{_r z^V%JhSyI(myw0Yn(@K(XyiThXauL%Wa)C|0z>@DogT+jdfY-K=*EZ8D&Ge!Kn(bXE zih(VPDLE`tQ^ks5oEO9GlEf;;l(S-(gcrkYA?L+_mx?iGvSOH;7sG8alNZBh+KS ' '; p++) { } /*一直读到空格为止*/ + for (; *p == ' '; p++) { } /*跳过空格*/ + + /*文件载入*/ + i = api_fopen(p); if (i == 0) { error("file not found.\n"); } + fsize = api_fsize(i, 0); + if (fsize > 512 * 1024) { + error("file too large.\n"); + } + api_fread(filebuf, fsize, i); + api_fclose(i); + + /*检查文件类型*/ + if (info_BMP(&env, info, fsize, filebuf) == 0) { + /*不是BMP */ + if (info_JPEG(&env, info, fsize, filebuf) == 0) { + /*也不是JPEG */ + api_putstr0("file type unknown.\n"); + api_end(); + } + } + /*上面其中一个info函数调用成功的话,info中包含以下信息 */ + /*info[0]:文件类型(1:BMP、2:JPEG)*/ + /*info[1]:颜色数信息*/ + /*info[2]:xsize */ + /* info[3] : ysize */ + + if (info[2] > 1024 || info[3] > 768) { + error("picture too large.\n"); + } + + /*窗口准备*/ + xsize = info[2] + 16; + if (xsize < 136) { + xsize = 136; + } + win = api_openwin(winbuf, xsize, info[3] + 37, -1, "gview"); + + /*将文件内容转换为图像数据*/ + if (info[0] == 1) { + i = decode0_BMP (&env, fsize, filebuf, 4, (char *) picbuf, 0); + } else { + i = decode0_JPEG(&env, fsize, filebuf, 4, (char *) picbuf, 0); + } + /*b_type = 4表示struct RGB格式*/ + /*skip设为0即可*/ + if (i != 0) { + error("decode error.\n"); + } + + /*显示*/ + for (i = 0; i < info[3]; i++) { + p = winbuf + (i + 29) * xsize + (xsize - info[2]) / 2; + q = picbuf + i * info[2]; + for (j = 0; j < info[2]; j++) { + p[j] = rgb2pal(q[j].r, q[j].g, q[j].b, j, i); + } + } + api_refreshwin(win, (xsize - info[2]) / 2, 29, (xsize - info[2]) / 2 + info[2], 29 + info[3]); + + /*等待结束*/ + for (;;) { + i = api_getkey(1); + if (i == 'Q' || i == 'q') { + api_end(); + } + } +} + +unsigned char rgb2pal(int r, int g, int b, int x, int y) +{ + static int table[4] = { 3, 1, 0, 2 }; + int i; + x &= 1; /*判断是偶数还是奇数*/ + y &= 1; + i = table[x + y * 2]; /*用于生成中间色的常量*/ + r = (r * 21) / 256; /*结果为0~20*/ + g = (g * 21) / 256; + b = (b * 21) / 256; + r = (r + i) / 4; /*结果为0~5*/ + g = (g + i) / 4; + b = (b + i) / 4; + return 16 + r + g * 6 + b * 36; +} + +void error(char *s) +{ + api_putstr0(s); + api_end(); +} diff --git a/30_day/gview/jpeg.c b/30_day/gview/jpeg.c new file mode 100644 index 0000000..1b37085 --- /dev/null +++ b/30_day/gview/jpeg.c @@ -0,0 +1,733 @@ +/* + * JPEG decoding engine for DCT-baseline + * + * copyrights 2003 by nikq | nikq::club. + * + * + */ + + +typedef unsigned char UCHAR; + +struct DLL_STRPICENV { int work[16384]; }; + +typedef struct +{ + int elem; + unsigned short code[256]; + unsigned char size[256]; + unsigned char value[256]; +}HUFF; + +typedef struct +{ + // SOF + int width; + int height; + // MCU + int mcu_width; + int mcu_height; + + int max_h,max_v; + int compo_count; + int compo_id[3]; + int compo_sample[3]; + int compo_h[3]; + int compo_v[3]; + int compo_qt[3]; + + // SOS + int scan_count; + int scan_id[3]; + int scan_ac[3]; + int scan_dc[3]; + int scan_h[3]; + int scan_v[3]; + int scan_qt[3]; + + // DRI + int interval; + + int mcu_buf[32*32*4]; + int *mcu_yuv[4]; + int mcu_preDC[3]; + + // DQT + int dqt[3][64]; + int n_dqt; + + // DHT + HUFF huff[2][3]; + + + // FILE i/o + unsigned char *fp, *fp1; + unsigned long bit_buff; + int bit_remain; + int width_buf; + + int base_img[64][64]; + + /* for dll + + JPEG *jpeg = (JPEG *)malloc(sizeof(JPEG) + 256); + */ + int dummy[64]; + +}JPEG; + +/* for 16bit */ +#ifndef PIXEL16 +#define PIXEL16(r, g, b) ((r) << 11 | (g) << 5 | (b)) + /* 0 <= r <= 31, 0 <= g <= 63, 0 <= b <= 31 */ +#endif + +int info_JPEG(struct DLL_STRPICENV *env, int *info, int size, UCHAR *fp); +int decode0_JPEG(struct DLL_STRPICENV *env, int size, UCHAR *fp, int b_type, UCHAR *buf, int skip); + +void jpeg_idct_init(int base_img[64][64]); +int jpeg_init(JPEG *jpeg); +// int jpeg_header(JPEG *jpge); +void jpeg_decode(JPEG *jpeg, unsigned char *rgb,int b_type); + +/* ----------------- start main section ----------------- */ + +int info_JPEG(struct DLL_STRPICENV *env,int *info, int size, UCHAR *fp0) +{ + JPEG *jpeg = (JPEG *) (((int *) env) + 128); + jpeg->fp = fp0; + jpeg->fp1 = fp0 + size; + +// if (512 + sizeof (JPEG) > 64 * 1024) +// return 0; + + if (jpeg_init(jpeg)) + return 0; +// jpeg_header(jpeg); + + if (jpeg->width == 0) + return 0; + + info[0] = 0x0002; + info[1] = 0x0000; + info[2] = jpeg->width; + info[3] = jpeg->height; + + /* OK */ + return 1; +} + +int decode0_JPEG(struct DLL_STRPICENV *env,int size, UCHAR *fp0, int b_type, UCHAR *buf, int skip) +{ + JPEG *jpeg = (JPEG *) (((int *) env) + 128); + jpeg->fp = fp0; + jpeg->fp1 = fp0 + size; + + jpeg_idct_init(jpeg->base_img); + jpeg_init(jpeg); +// jpeg_header(jpeg); + +// if (jpeg->width == 0) +// return 8; + /* decode*/ + + jpeg->width_buf = skip / (b_type & 0x7f) + jpeg->width; + jpeg_decode(jpeg, buf, b_type); + + /* OK */ + return 0; +} + +// -------------------------- I/O ---------------------------- + +unsigned short get_bits(JPEG *jpeg, int bit) +{ + unsigned char c, c2; + unsigned short ret; + unsigned long buff; + int remain; + + buff = jpeg->bit_buff; + remain = jpeg->bit_remain; + + while (remain <= 16) { + if (jpeg->fp >= jpeg->fp1) { + ret = 0; + goto fin; + } + c = *jpeg->fp++; + if (c == 0xff) { + if (jpeg->fp >= jpeg->fp1) { + ret = 0; + goto fin; + } + jpeg->fp++; /* 00 skip */ + } + buff = (buff << 8) | c; + remain += 8; + } + ret = (buff >> (remain - bit)) & ((1 << bit) - 1); + remain -= bit; + + jpeg->bit_remain = remain; + jpeg->bit_buff = buff; +fin: + return ret; +} + +// ------------------------ JPEG ----------------- + +// start of frame +int jpeg_sof(JPEG *jpeg) +{ + unsigned char c; + int i, h, v, n; + + if (jpeg->fp + 8 > jpeg->fp1) + goto err; + /* fp[2] ‚Í bpp */ + jpeg->height = jpeg->fp[3] << 8 | jpeg->fp[4]; + jpeg->width = jpeg->fp[5] << 8 | jpeg->fp[6]; + n = jpeg->compo_count = jpeg->fp[7]; // Num of compo, nf + jpeg->fp += 8; + if (jpeg->fp + n * 3 > jpeg->fp1) + goto err; + + for (i = 0; i < n; i++) { + jpeg->compo_id[i] = jpeg->fp[0]; + + jpeg->compo_sample[i] = c = jpeg->fp[1]; + h = jpeg->compo_h[i] = (c >> 4) & 0x0f; + v = jpeg->compo_v[i] = c & 0x0f; + + if (jpeg->max_h < h) + jpeg->max_h = h; + if (jpeg->max_v < v) + jpeg->max_v = v; + + jpeg->compo_qt[i] = jpeg->fp[2]; + jpeg->fp += 3; + } + return 0; +err: + jpeg->fp = jpeg->fp1; + return 1; +} + +// define quantize table +int jpeg_dqt(JPEG *jpeg) +{ + unsigned char c; + int i, j, v, size; + + if (jpeg->fp + 2 > jpeg->fp1) + goto err; + size = (jpeg->fp[0] << 8 | jpeg->fp[1]) - 2; + jpeg->fp += 2; + if (jpeg->fp + size > jpeg->fp1) + goto err; + + while (size > 0) { + c = *jpeg->fp++; + size--; + j = c & 7; + if (j > jpeg->n_dqt) + jpeg->n_dqt = j; + + if (c & 0xf8) { + // 16 bit DQT + for (i = 0; i < 64; i++) { + jpeg->dqt[j][i] = jpeg->fp[0]; + jpeg->fp += 2; + } + size += -64 * 2; + } else { + // 8 bit DQT + for (i = 0; i < 64; i++) + jpeg->dqt[j][i] = *jpeg->fp++; + size -= 64; + } + } + return 0; +err: + jpeg->fp = jpeg->fp1; + return 1; +} + +// define huffman table +int jpeg_dht(JPEG *jpeg) +{ + unsigned tc, th; + unsigned code = 0; + unsigned char val; + int i, j, k, num, Li[17]; + int len, max_val; + HUFF *table; + + if (jpeg->fp + 2 > jpeg->fp1) + goto err; + len = (jpeg->fp[0] << 8 | jpeg->fp[1]) - 2; + jpeg->fp += 2; + + while (len > 0) { + if (jpeg->fp + 17 > jpeg->fp1) + goto err; + val = jpeg->fp[0]; + + tc = (val >> 4) & 0x0f; + th = val & 0x0f; + table = &(jpeg->huff[tc][th]); + + num = 0; + k = 0; + for (i = 1; i <= 16; i++) { + Li[i] = jpeg->fp[i]; + num += Li[i]; + for (j = 0; j < Li[i]; j++) + table->size[k++] = i; + } + table->elem = num; + jpeg->fp += 17; + + k=0; + code=0; + i = table->size[0]; + while (k < num) { + while (table->size[k] == i) + table->code[k++] = code++; + if (k >= num) + break; + do { + code <<= 1; + i++; + } while (table->size[k] != i); + } + + if (jpeg->fp + num > jpeg->fp1) + goto err; + for (k = 0; k < num; k++) + table->value[k] = jpeg->fp[k]; + jpeg->fp += num; + + len -= 18 + num; + } + return 0; +err: + jpeg->fp = jpeg->fp1; + return 1; +} + +int jpeg_init(JPEG *jpeg) +{ + unsigned char c; + int r = 0, i; + jpeg->width = 0; + jpeg->mcu_preDC[0] = 0; + jpeg->mcu_preDC[1] = 0; + jpeg->mcu_preDC[2] = 0; + jpeg->n_dqt = 0; + jpeg->max_h = 0; + jpeg->max_v = 0; + jpeg->bit_remain = 0; + jpeg->bit_buff = 0; + + jpeg->interval = 0; +// return; +//} +// +//int jpeg_header(JPEG *jpeg) +//{ +// unsigned char c; +// int r = 0, i; + + for (;;) { + if (jpeg->fp + 2 > jpeg->fp1) + goto err; + if (jpeg->fp[0] != 0xff) + goto err0; + c = jpeg->fp[1]; + jpeg->fp += 2; + if (c == 0xd8) + continue; /* SOI */ + if (c == 0xd9) + goto err; /* EOI */ + + if (c == 0xc0) + jpeg_sof(jpeg); + else if (c == 0xc4) + jpeg_dht(jpeg); + else if (c == 0xdb) + jpeg_dqt(jpeg); + else if (c == 0xdd) { + if (jpeg->fp + 4 > jpeg->fp1) + goto err; + jpeg->interval = jpeg->fp[2] << 8 | jpeg->fp[3]; + jpeg->fp += 4; + } else if (c == 0xda) { + if (jpeg->fp + 3 > jpeg->fp1) + goto err; + jpeg->scan_count = jpeg->fp[2]; + jpeg->fp += 3; + if (jpeg->fp + jpeg->scan_count * 2 > jpeg->fp1) + goto err; + for (i = 0; i < jpeg->scan_count; i++) { + jpeg->scan_id[i] = jpeg->fp[0]; + jpeg->scan_dc[i] = jpeg->fp[1] >> 4; // DC Huffman Table + jpeg->scan_ac[i] = jpeg->fp[1] & 0x0F; // AC Huffman Table + jpeg->fp += 2; + } + jpeg->fp += 3; /* 3bytes skip */ + goto fin; + } else { + if (jpeg->fp + 2 > jpeg->fp1) + goto err; + jpeg->fp += jpeg->fp[0] << 8 | jpeg->fp[1]; + } + } +err: + jpeg->fp = jpeg->fp1; +err0: + r++; +fin: + return r; +} + +// MCU decode + +void jpeg_decode_init(JPEG *jpeg) +{ + int i, j; + + for (i = 0; i < jpeg->scan_count; i++) { + // i:scan + for (j = 0; j < jpeg->compo_count; j++) { + // j:frame + if (jpeg->scan_id[i] == jpeg->compo_id[j]) { + jpeg->scan_h[i] = jpeg->compo_h[j]; + jpeg->scan_v[i] = jpeg->compo_v[j]; + jpeg->scan_qt[i] = jpeg->compo_qt[j]; + break; + } + } + // if (j >= jpeg->compo_count) + // return 1; + } + jpeg->mcu_width = jpeg->max_h * 8; + jpeg->mcu_height = jpeg->max_v * 8; + + for (i = 0; i < 32 * 32 * 4; i++) + jpeg->mcu_buf[i] = 0x80; + + for (i = 0; i < jpeg->scan_count; i++) + jpeg->mcu_yuv[i] = jpeg->mcu_buf + (i << 10); + return; +} + +int jpeg_huff_decode(JPEG *jpeg,int tc,int th) +{ + HUFF *h = &(jpeg->huff[tc][th]); + int code,size,k,v; + code = 0; + size = 0; + k = 0; + while( size < 16 ){ + size++; + v = get_bits(jpeg,1); + if(v < 0){ + return v; + } + code = (code << 1) | v; + + while(h->size[k] == size){ + if(h->code[k] == code){ + return h->value[k]; + } + k++; + } + } + + return -1; +} + +void jpeg_idct_init(int base_img[64][64]) +{ + int u, v, m, n; + int tmpm[8], tmpn[8]; + int cost[32]; + cost[ 0] = 32768; cost[ 1] = 32138; cost[ 2] = 30274; cost[ 3] = 27246; cost[ 4] = 23170; cost[ 5] = 18205; cost[ 6] = 12540; cost[ 7] = 6393; + cost[ 8] = 0; cost[ 9] = -6393; cost[10] = -12540; cost[11] = -18205; cost[12] = -23170; cost[13] = -27246; cost[14] = -30274; cost[15] = -32138; + for (u = 0; u < 16; u++) + cost[u + 16] = - cost[u]; + + for (u = 0; u < 8; u++) { + { + int i=u, d=u*2; + if (d == 0) + i = 4; + for (m = 0; m < 8; m++){ + tmpm[m] = cost[i]; + i=(i+d)&31; + } + } + for (v = 0; v < 8; v++) { + { + int i=v,d=v*2; + if (d == 0) + i=4; + for (n = 0; n < 8; n++){ + tmpn[n] = cost[i]; + i=(i+d)&31; + } + } + + for (m = 0; m < 8; m++) { + for (n = 0; n < 8; n++) { + base_img[u * 8 + v][m * 8 + n] = (tmpm[m] * tmpn[n])>>15; + } + } + } + } + return; +} + +void jpeg_idct(int *block, int *dest, int base_img[64][64]) +{ + int i, j ,k; + + for (i = 0; i < 64; i++) + dest[i] = 0; + + for (i = 0; i < 64; i++) { + k = block[i]; + if(k) { + for (j = 0; j < 64; j++) { + dest[j] += k * base_img[i][j]; + } + } + } + + for (i = 0; i < 64; i++) + dest[i] >>= 17; + return; +} + + +int jpeg_get_value(JPEG *jpeg,int size) +{ + int val = 0; + if (size) { + val = get_bits(jpeg,size); + if (val < 0) + val = 0x10000 | (0 - val); + else if (!(val & (1<<(size-1)))) + val -= (1 << size) - 1; + } + return val; +} + +int jpeg_decode_huff(JPEG *jpeg,int scan,int *block, UCHAR *zigzag_table) +{ + int size, len, val, run, index; + int *pQt = (int *)(jpeg->dqt[jpeg->scan_qt[scan]]); + + // DC + size = jpeg_huff_decode(jpeg,0,jpeg->scan_dc[scan]); + if(size < 0) + return 0; + val = jpeg_get_value(jpeg,size); + jpeg->mcu_preDC[scan] += val; + block[0] = jpeg->mcu_preDC[scan] * pQt[0]; + + //AC + index = 1; + while(index<64) + { + size = jpeg_huff_decode(jpeg,1,jpeg->scan_ac[scan]); + if(size < 0) + break; + // EOB + if(size == 0) + break; + + // RLE + run = (size>>4)&0xF; + size = size & 0x0F; + + val = jpeg_get_value(jpeg,size); + if(val>=0x10000) { + return val; + } + + // ZRL + while (run-- > 0) + block[ zigzag_table[index++] ] = 0; + + block[ zigzag_table[index] ] = val * pQt[index]; + index++; + } + while(index<64) + block[zigzag_table[index++]]=0; + return 0; +} + +void jpeg_mcu_bitblt(int *src, int *dest, int width, + int x0, int y0, int x1, int y1) +{ + int w, h; + int x, y, x2, y2; + w = x1 - x0; + h = y1 - y0; + dest += y0 * width + x0; + width -= w; + + for (y = 0; y < h; y++) { + y2 = (y * 8 / h) * 8; + for (x = 0; x < w; x++) + *dest++ = src[y2 + (x * 8 / w)]; + dest += width; + } +} + +int jpeg_decode_mcu(JPEG *jpeg, UCHAR *zigzag_table) +{ + int scan, val; + int unit, i, h, v; + int *p, hh, vv; + int block[64], dest[64]; + + // mcu_width x mcu_height + for (scan = 0; scan < jpeg->scan_count; scan++) { + hh = jpeg->scan_h[scan]; + vv = jpeg->scan_v[scan]; + for (v = 0; v < vv; v++) { + for (h = 0; h < hh; h++) { + // ƒuƒƒbƒN(8x8)‚̃fƒR[ƒh + val = jpeg_decode_huff(jpeg, scan, block, zigzag_table); + // if(val>=0x10000){ + // printf("marker found:%02x\n",val); + // } + + jpeg_idct(block, dest, jpeg->base_img); + + p = jpeg->mcu_buf + (scan << 10); + + jpeg_mcu_bitblt(dest, p, jpeg->mcu_width, + jpeg->mcu_width * h / hh, jpeg->mcu_height * v / vv, + jpeg->mcu_width * (h + 1) / hh, jpeg->mcu_height * (v + 1) / vv); + } + } + } +} + +// YCrCb=>RGB + +int jpeg_decode_yuv(JPEG *jpeg, int h, int v, unsigned char *rgb, int b_type) +{ + int x0, y0, x, y, x1, y1; + int *py; + int Y12, V; + int mw, mh, w; + int i; + + mw = jpeg->mcu_width; + mh = jpeg->mcu_height; + + x0 = h * jpeg->max_h * 8; + y0 = v * jpeg->max_v * 8; + + x1 = jpeg->width - x0; + if (x1 > mw) + x1 = mw; + y1 = jpeg->height - y0; + if (y1 > mh) + y1 = mh; + + py = jpeg->mcu_buf; + rgb += (y0 * jpeg->width_buf + x0) * (b_type & 0x7f); + w = (jpeg->width_buf - x1) * (b_type & 0x7f); + + for (y = 0; y < y1; y++) { + for (x = 0; x < x1; x++) { + int b, g, r; + Y12 = py[0] << 12; + // U = py[1024]; /* pu */ + V = py[2048]; /* pv */ + + /* blue */ + b = 128 + ((Y12 - V * 4 + py[1024] /* pu */ * 0x1C59) >> 12); + if (b & 0xffffff00) + b = (~b) >> 24; + + /* green */ + g = 128 + ((Y12 - V * 0x0B6C) >> 12); + if (g & 0xffffff00) + g = (~g) >> 24; + + /* red */ + r = 128 + ((Y12 + V * 0x166E) >> 12); + if (r & 0xffffff00) + r = (~r) >> 24; + if (b_type == 0x0004) { + rgb[0] = b; + rgb[1] = g; + rgb[2] = r; + py++; + rgb += 4; + } else if (b_type == 0x0002) { + r &= 0xff; + g &= 0xff; + b &= 0xff; + *(short *) rgb = PIXEL16(r >> 3, g >> 2, b >> 3); + rgb += 2; + } + } + py += mw - x1; + rgb += w; + } + return; +} + +#define INIT_ZTABLE(i, b0, b1, b2, b3) *(int *) &zigzag_table[i] = b0 | b1 << 8 | b2 << 16 | b3 << 24 + +void jpeg_decode(JPEG *jpeg, UCHAR *rgb, int b_type) +{ + int h_unit, v_unit; + int mcu_count, h, v; + int val; + unsigned char m; + + UCHAR zigzag_table[64]; + + INIT_ZTABLE( 0, 0, 1, 8, 16); INIT_ZTABLE( 4, 9, 2, 3, 10); + INIT_ZTABLE( 8, 17, 24, 32, 25); INIT_ZTABLE(12, 18, 11, 4, 5); + INIT_ZTABLE(16, 12, 19, 26, 33); INIT_ZTABLE(20, 40, 48, 41, 34); + INIT_ZTABLE(24, 27, 20, 13, 6); INIT_ZTABLE(28, 7, 14, 21, 28); + INIT_ZTABLE(32, 35, 42, 49, 56); INIT_ZTABLE(36, 57, 50, 43, 36); + INIT_ZTABLE(40, 29, 22, 15, 23); INIT_ZTABLE(44, 30, 37, 44, 51); + INIT_ZTABLE(48, 58, 59, 52, 45); INIT_ZTABLE(52, 38, 31, 39, 46); + INIT_ZTABLE(56, 53, 60, 61, 54); INIT_ZTABLE(60, 47, 55, 62, 63); + + jpeg_decode_init(jpeg); + + h_unit = (jpeg->width + jpeg->mcu_width - 1) / jpeg->mcu_width; + v_unit = (jpeg->height + jpeg->mcu_height - 1) / jpeg->mcu_height; + + mcu_count = 0; + for (v = 0; v < v_unit; v++) { + for (h = 0; h < h_unit; h++) { + mcu_count++; + jpeg_decode_mcu(jpeg, zigzag_table); + jpeg_decode_yuv(jpeg, h, v, rgb, b_type & 0x7fff); + if (jpeg->interval > 0 && mcu_count >= jpeg->interval) { + jpeg->bit_remain -= (jpeg->bit_remain & 7); + jpeg->bit_remain -= 8; + jpeg->mcu_preDC[0] = 0; + jpeg->mcu_preDC[1] = 0; + jpeg->mcu_preDC[2] = 0; + mcu_count = 0; + } + } + } + return; +} + diff --git a/30_day/gview/make.bat b/30_day/gview/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/gview/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/pictdata/fujisan.jpg b/30_day/pictdata/fujisan.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c2aa328825ff945a89a1a8b8e9128313ea7de0b6 GIT binary patch literal 15297 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 Tgz|2dIU63DE4D8!LvRc&<=LTv literal 0 HcmV?d00001 diff --git a/30_day/pictdata/fujisan_.jpg b/30_day/pictdata/fujisan_.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6e041b105087d4861fa2d4055ecef13068623cce GIT binary patch literal 15978 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 literal 0 HcmV?d00001 diff --git a/30_day/pictdata/night.bmp b/30_day/pictdata/night.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2e0f1cf43c0b6936739b291db8873dd159165508 GIT binary patch literal 666 zcmV;L0%iS)|Ns910000_Q$bTpLrqYC?G?T`03><*6@^MDAAXuDtFQ*4Gt2PtPbK!l zRI1=nHt*~|j|hs6Vf32boY&;>3k(BK-+O_cj2AP;hgNO^MBqd;RU-xqYc^j*&CWj; zowj-lni8+2-n-f3KXzJe#*4<$##|O*FS%|@;KrYu1>_SvM)Y!OMT5#yyaD^2Cj0C! zA*b1&A791EANIG<0(AZYGLKLZ_Eczr^%C<^iX{-NDN&!^-E(zc85e8#_u!VUGGmV6 z5kYngjJXh|V~3ZbF$z93wHZuRA|Ix>O`*;6hdT?hSW8a8-dXvma@Men(avlQn)%-U zA9MUn56nop2ia-)B(jZ|pY*l zh%wxPvjv0m_vgc~bh?v#_bh}2Nw^@Mw;t;2MuqQha=DRFp%QN0Yk_Lyl~}a~%N860 z?I#I&2kBhj1gD??H_=%MIYgP?6CScM*UtbFUKE4*Bn@X&eE9;fsv{U*^mR3R|mLXGN%gGjj1%ah~*Ae5ZwW1$CyVtK2CkutsONG4x*5 zL4RcfRMmeiBxiNqrH<&_;JvH}On3Pj&pSV!u)}?++VQ1N^zMMRb-XgoRAP`H425feEDM?|WI5-^KG$)!v+%9j2nra$o32CD-aun+;CUoPic(Q(8I6Gx z#$BSw_ffxH>2KekzAkJ}c>aaY-}&>$@&%sQKWSO$Q`_^h;BR?;mIhC__&hJKudhhF z^WXCRP98q^M1CcKk9B6|w@ls5|q=lx-m5(HC2)Fr`8xy(JEK87Ftj{P;8#DhPu&XURz&KL3xyvWk9;_1|F2`JAP(`F7P$Ef? zp97Rr%Ah0EVfWXix>XX1fRM3ID;9?j;ocQs5z}~RXBCv6nc>1v zQ+P)uP-No>x&jfMdBn~pd4I!J1)yK~{UiGszXoWtZg2jC6GaZXR^ zo~{$sfr0HCE8Z?Y`TB`8aSRlMbq9q=BbVwjE1emXOW~00}*}dz9RoFPn@%~AI zpPK=6q?M`knoo%H4mEencL}XG<)Pcyr@TSVL0o#C)|k`L1bkP0}T_K1G+Q3lh6&kBkQIg<#hwQ18Ac2i)WsH z3GdOF?++B+!_2!>=WWyZ8U=j#bs?Q@g>NJNC6LlNc~1R^58oHy-69p&H-Pnbjs(ii z0`mBU=Rm{0p z=J)WN4X7R2t~wUpvsz-kXt%1>m@;-EK32w2UVfaKiW2{k`8GvAcGeAyF7XcxPyc&7 kg46KlNzF&VKQjFAr^&=DKJYaOt39;#eg6>_{e6S~0d7O!!~g&Q literal 0 HcmV?d00001 From 0e31ff06caa6cb7a2d14089515c63a62d4189690 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 20 May 2016 14:27:07 +0800 Subject: [PATCH 68/83] bug fix --- 30_day/a/Makefile | 3 + 30_day/apilib/apilib.lib | Bin 8966 -> 0 bytes 30_day/haribote/bootpack.h | 20 +++---- 30_day/haribote/console.c | 104 +++++++++++++++++------------------ 30_day/haribote/haribote.sys | Bin 33331 -> 0 bytes 30_day/haribote/ipl20.nas | 6 +- 30_day/haribote/mouse.c | 16 +++--- 30_day/haribote/mtask.c | 35 ++++++------ 30_day/haribote/tek.c | 10 ++-- 9 files changed, 98 insertions(+), 96 deletions(-) delete mode 100644 30_day/apilib/apilib.lib delete mode 100644 30_day/haribote/haribote.sys diff --git a/30_day/a/Makefile b/30_day/a/Makefile index 674a683..5539044 100644 --- a/30_day/a/Makefile +++ b/30_day/a/Makefile @@ -3,3 +3,6 @@ STACK = 1k MALLOC = 0k include ../app_make.txt + +$(APP).hrb : $(APP).org Makefile + $(COPY) $(APP).org $(APP).hrb diff --git a/30_day/apilib/apilib.lib b/30_day/apilib/apilib.lib deleted file mode 100644 index 29a8eeebd154eb753bb6d0e59a2125dff5d57df1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8966 zcmeI2&uv5w%5XY3zgzHW)jywS}zIi{^ zs~^`oyY){J*V10ed5ca-)fYK*TCxI?b?20d;e=|w_fW&6}na@=PnqsV7Bha zllH#Z`liuxcX5h4?T34frc-RR8rFkav)SI2z1`<~9n-YOXg6AxJnfiN-K{$VG#f3` zDeN}e-9hQDY27!!m6wTISd9m!{SkCHS})$E;`RZ|rK z#|@ljv<` zk{TKXJq@0(S4Kv|fTU3jLBsIt#Z#JokY1dkHm1RSlte+J&l|wuM!?oo)Fa?YdgWaq z5Jr@J91^)TiH%C^Mx_v|Uh=Q{?=)o4s((anyz1OXNffL8`Da^wa!*(bQavlP)H}#5 z_bQnc(ug!^#8=xvJ5)&zgy-*-cLjt;4X_o;1C=^a4ne2vx7mNteS+v*rZ%R-eUwB) z=hLk|d5(-{iSR5Fo)yBACOny5Gjo{`-413{)-&R#@Je)y7U@RHA0;cozPqG!{eMD< zcOXHjLX}Af!2ca!tG6Ds^wv0udn73()F@y8O#*o;b z_d>5k$H8&G?9V=eLYT<^1PVXU?+X7jr?#AXi()kkTw9nBbg=@*)j4->8D{hBcrR-3nB Wt<|Qd)cUcbwAxHvcu(R_7XJe03V>?> diff --git a/30_day/haribote/bootpack.h b/30_day/haribote/bootpack.h index bb195ff..aa970dc 100644 --- a/30_day/haribote/bootpack.h +++ b/30_day/haribote/bootpack.h @@ -88,16 +88,16 @@ struct GATE_DESCRIPTOR { void init_gdtidt(void); void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar); void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar); -#define ADR_IDT 0x0026f800 -#define LIMIT_IDT 0x000007ff -#define ADR_GDT 0x00270000 -#define LIMIT_GDT 0x0000ffff +#define ADR_IDT 0x0026f800 +#define LIMIT_IDT 0x000007ff +#define ADR_GDT 0x00270000 +#define LIMIT_GDT 0x0000ffff #define ADR_BOTPAK 0x00280000 #define LIMIT_BOTPAK 0x0007ffff #define AR_DATA32_RW 0x4092 #define AR_CODE32_ER 0x409a -#define AR_LDT 0x0082 -#define AR_TSS32 0x0089 +#define AR_LDT 0x0082 +#define AR_TSS32 0x0089 #define AR_INTGATE32 0x008e /* int.c */ @@ -288,10 +288,10 @@ void file_loadfile(int clustno, int size, char *buf, int *fat, char *img); struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max); char *file_loadfile2(int clustno, int *psize, int *fat); -/* bootpack.c */ -struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal); -struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal); - /* tek.c */ int tek_getsize(unsigned char *p); int tek_decomp(unsigned char *p, char *q, int size); + +/* bootpack.c */ +struct TASK *open_constask(struct SHEET *sht, unsigned int memtotal); +struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal); diff --git a/30_day/haribote/console.c b/30_day/haribote/console.c index 3e51686..e8c5c69 100644 --- a/30_day/haribote/console.c +++ b/30_day/haribote/console.c @@ -9,8 +9,8 @@ void console_task(struct SHEET *sheet, int memtotal) struct TASK *task = task_now(); struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; int i, *fat = (int *) memman_alloc_4k(memman, 4 * 2880); - struct FILEHANDLE fhandle[8]; struct CONSOLE cons; + struct FILEHANDLE fhandle[8]; char cmdline[30]; unsigned char *nihongo = (char *) *((int *) 0x0fe8); @@ -133,19 +133,19 @@ void cons_putchar(struct CONSOLE *cons, int chr, char move) cons_newline(cons); } if (((cons->cur_x - 8) & 0x1f) == 0) { - break; /*被32整除则break*/ + break; /* 32�Ŋ���؂ꂽ��break */ } } - } else if (s[0] == 0x0a) { /*换行*/ + } else if (s[0] == 0x0a) { /* ���s */ cons_newline(cons); - } else if (s[0] == 0x0d) { /*回车*/ - /*先不做任何操作*/ - } else { /*一般字符*/ + } else if (s[0] == 0x0d) { /* ���A */ + /* �Ƃ肠�����Ȃɂ����Ȃ� */ + } else { /* ���ʂ̕��� */ if (cons->sht != 0) { putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1); } if (move != 0) { - /* move为0时光标不后移*/ + /* move��0�̂Ƃ��̓J�[�\����i�߂Ȃ� */ cons->cur_x += 8; if (cons->cur_x == 8 + 240) { cons_newline(cons); @@ -161,9 +161,9 @@ void cons_newline(struct CONSOLE *cons) struct SHEET *sheet = cons->sht; struct TASK *task = task_now(); if (cons->cur_y < 28 + 112) { - cons->cur_y += 16; /*到下一行*/ + cons->cur_y += 16; /* ���̍s�� */ } else { - /*滚动*/ + /* �X�N���[�� */ if (sheet != 0) { for (y = 28; y < 28 + 112; y++) { for (x = 8; x < 8 + 240; x++) { @@ -180,7 +180,7 @@ void cons_newline(struct CONSOLE *cons) } cons->cur_x = 8; if (task->langmode == 1 && task->langbyte1 != 0) { - cons->cur_x += 8; + cons->cur_x = 16; } return; } @@ -208,7 +208,7 @@ void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) cmd_mem(cons, memtotal); } else if (strcmp(cmdline, "cls") == 0 && cons->sht != 0) { cmd_cls(cons); - } else if ((strcmp(cmdline, "dir") == 0 || strcmp(cmdline, "ls") == 0) && cons->sht != 0) { + } else if (strcmp(cmdline, "dir") == 0 && cons->sht != 0) { cmd_dir(cons); } else if (strcmp(cmdline, "exit") == 0) { cmd_exit(cons, fat); @@ -218,9 +218,9 @@ void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) cmd_ncst(cons, cmdline, memtotal); } else if (strncmp(cmdline, "langmode ", 9) == 0) { cmd_langmode(cons, cmdline); - }else if (cmdline[0] != 0) { + } else if (cmdline[0] != 0) { if (cmd_app(cons, fat, cmdline) == 0) { - /*不是命令,不是应用程序,也不是空行*/ + /* �R�}���h�ł͂Ȃ��A�A�v���ł��Ȃ��A����ɋ�s�ł��Ȃ� */ cons_putstr0(cons, "Bad command.\n\n"); } } @@ -288,9 +288,9 @@ void cmd_exit(struct CONSOLE *cons, int *fat) memman_free_4k(memman, (int) fat, 4 * 2880); io_cli(); if (cons->sht != 0) { - fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); /* 768〜1023 */ + fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); /* 768�`1023 */ } else { - fifo32_put(fifo, task - taskctl->tasks0 + 1024); /*1024~2023*/ + fifo32_put(fifo, task - taskctl->tasks0 + 1024); /* 1024�`2023 */ } io_sti(); for (;;) { @@ -306,11 +306,11 @@ void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal) int i; sheet_slide(sht, 32, 4); sheet_updown(sht, shtctl->top); - /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ + /* �R�}���h���C���ɓ��͂��ꂽ��������A�ꕶ�����V�����R���\�[���ɓ��� */ for (i = 6; cmdline[i] != 0; i++) { fifo32_put(fifo, cmdline[i] + 256); } - fifo32_put(fifo, 10 + 256); /*回车键*/ + fifo32_put(fifo, 10 + 256); /* Enter */ cons_newline(cons); return; } @@ -320,12 +320,11 @@ void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal) struct TASK *task = open_constask(0, memtotal); struct FIFO32 *fifo = &task->fifo; int i; - - /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ + /* �R�}���h���C���ɓ��͂��ꂽ��������A�ꕶ�����V�����R���\�[���ɓ��� */ for (i = 5; cmdline[i] != 0; i++) { fifo32_put(fifo, cmdline[i] + 256); } - fifo32_put(fifo, 10 + 256); /*回车键*/ + fifo32_put(fifo, 10 + 256); /* Enter */ cons_newline(cons); return; } @@ -347,26 +346,25 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) { struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; struct FILEINFO *finfo; - struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; char name[18], *p, *q; struct TASK *task = task_now(); int i, segsiz, datsiz, esp, dathrb, appsiz; struct SHTCTL *shtctl; struct SHEET *sht; - /*根据命令行生成文件名*/ + /* �R�}���h���C������t�@�C�����𐶐� */ for (i = 0; i < 13; i++) { if (cmdline[i] <= ' ') { break; } name[i] = cmdline[i]; } - name[i] = 0; /*暂且将文件名的后面置为0*/ + name[i] = 0; /* �Ƃ肠�����t�@�C�����̌���0�ɂ��� */ - /*寻找文件 */ + /* �t�@�C����T�� */ finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); if (finfo == 0 && name[i - 1] != '.') { - /*由于找不到文件,故在文件名后面加上“.hrb”后重新寻找*/ + /* ���‚���Ȃ������̂Ō���".HRB"���‚��Ă�����x�T���Ă݂� */ name[i ] = '.'; name[i + 1] = 'H'; name[i + 2] = 'R'; @@ -376,7 +374,7 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) } if (finfo != 0) { - /*如果找到文件*/ + /* �t�@�C�������‚������ꍇ */ appsiz = finfo->size; p = file_loadfile2(finfo->clustno, &appsiz, fat); if (appsiz >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) { @@ -386,8 +384,8 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) dathrb = *((int *) (p + 0x0014)); q = (char *) memman_alloc_4k(memman, segsiz); task->ds_base = (int) q; - set_segmdesc(task->ldt + 0, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); - set_segmdesc(task->ldt + 1, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); + set_segmdesc(task->ldt + 0, appsiz - 1, (int) p, AR_CODE32_ER + 0x60); + set_segmdesc(task->ldt + 1, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); for (i = 0; i < datsiz; i++) { q[esp + i] = p[dathrb + i]; } @@ -396,11 +394,11 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) for (i = 0; i < MAX_SHEETS; i++) { sht = &(shtctl->sheets0[i]); if ((sht->flags & 0x11) == 0x11 && sht->task == task) { - /*找到被应用程序遗留的窗口*/ - sheet_free(sht); /*关闭*/ + /* �A�v�����J�����ςȂ��ɂ����������𔭌� */ + sheet_free(sht); /* �‚��� */ } } - for (i = 0; i < 8; i++) { /*将未关闭的文件关闭*/ + for (i = 0; i < 8; i++) { /* �N���[�Y���ĂȂ��t�@�C�����N���[�Y */ if (task->fhandle[i].buf != 0) { memman_free_4k(memman, (int) task->fhandle[i].buf, task->fhandle[i].size); task->fhandle[i].buf = 0; @@ -416,7 +414,7 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) cons_newline(cons); return 1; } - /*没有找到文件的情况*/ + /* �t�@�C�������‚���Ȃ������ꍇ */ return 0; } @@ -428,8 +426,8 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); struct SHEET *sht; struct FIFO32 *sys_fifo = (struct FIFO32 *) *((int *) 0x0fec); - int *reg = &eax + 1; /* eax后面的地址*/ - /*强行改写通过PUSHAD保存的值*/ + int *reg = &eax + 1; /* eax�̎��̔Ԓn */ + /* �ۑ��̂��߂�PUSHAD�������ɏ��������� */ /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */ /* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ int i; @@ -452,7 +450,7 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax); make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0); sheet_slide(sht, ((shtctl->xsize - esi) / 2) & ~3, (shtctl->ysize - edi) / 2); - sheet_updown(sht, shtctl->top); /*将窗口图层高度指定为当前鼠标所在图层的高度,鼠标移到上层*/ + sheet_updown(sht, shtctl->top); /* ���̃}�E�X�Ɠ��������ɂȂ�悤�Ɏw��F �}�E�X�͂��̏�ɂȂ� */ reg[7] = (int) sht; } else if (edx == 6) { sht = (struct SHEET *) (ebx & 0xfffffffe); @@ -468,13 +466,13 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int } } else if (edx == 8) { memman_init((struct MEMMAN *) (ebx + ds_base)); - ecx &= 0xfffffff0; /*以16字节为单位*/ + ecx &= 0xfffffff0; /* 16�o�C�g�P�ʂ� */ memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); } else if (edx == 9) { - ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + ecx = (ecx + 0x0f) & 0xfffffff0; /* 16�o�C�g�P�ʂɐ؂�グ */ reg[7] = memman_alloc((struct MEMMAN *) (ebx + ds_base), ecx); } else if (edx == 10) { - ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ + ecx = (ecx + 0x0f) & 0xfffffff0; /* 16�o�C�g�P�ʂɐ؂�グ */ memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); } else if (edx == 11) { sht = (struct SHEET *) (ebx & 0xfffffffe); @@ -508,7 +506,7 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int io_cli(); if (fifo32_status(&task->fifo) == 0) { if (eax != 0) { - task_sleep(task); /* FIFO为空,休眠并等待*/ + task_sleep(task); /* FIFO����Ȃ̂ŐQ�đ҂� */ } else { io_sti(); reg[7] = -1; @@ -517,32 +515,32 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int } i = fifo32_get(&task->fifo); io_sti(); - if (i <= 1) { /*光标用定时器*/ - /*应用程序运行时不需要显示光标,因此总是将下次显示用的值置为1*/ - timer_init(cons->timer, &task->fifo, 1); /*下次置为1*/ + if (i <= 1 && cons->sht != 0) { /* �J�[�\���p�^�C�} */ + /* �A�v�����s���̓J�[�\�����o�Ȃ��̂ŁA���‚����͕\���p��1�𒍕����Ă��� */ + timer_init(cons->timer, &task->fifo, 1); /* ����1�� */ timer_settime(cons->timer, 50); } - if (i == 2) { /*光标ON */ + if (i == 2) { /* �J�[�\��ON */ cons->cur_c = COL8_FFFFFF; } - if (i == 3) { /*光标OFF */ + if (i == 3) { /* �J�[�\��OFF */ cons->cur_c = -1; } - if (i == 4) { /*只关闭命令行窗口*/ + if (i == 4) { /* �R���\�[��������‚��� */ timer_cancel(cons->timer); io_cli(); - fifo32_put(sys_fifo, cons->sht - shtctl->sheets0 + 2024); /*2024~2279*/ + fifo32_put(sys_fifo, cons->sht - shtctl->sheets0 + 2024); /* 2024�`2279 */ cons->sht = 0; io_sti(); } - if (i >= 256) { /*键盘数据(通过任务A)等*/ + if (i >= 256) { /* �L�[�{�[�h�f�[�^�i�^�X�NA�o�R�j�Ȃ� */ reg[7] = i - 256; return 0; } } } else if (edx == 16) { reg[7] = (int) timer_alloc(); - ((struct TIMER *) reg[7])->flags2 = 1; /*允许自动取消*/ + ((struct TIMER *) reg[7])->flags2 = 1; /* �����L�����Z���L�� */ } else if (edx == 17) { timer_init((struct TIMER *) ebx, &task->fifo, eax + 256); } else if (edx == 18) { @@ -570,13 +568,13 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int fh = &task->fhandle[i]; reg[7] = 0; if (i < 8) { - finfo = file_search((char *) ebx + ds_base, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); + finfo = file_search((char *) ebx + ds_base, + (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); if (finfo != 0) { reg[7] = (int) fh; - fh->buf = (char *) memman_alloc_4k(memman, finfo->size); fh->size = finfo->size; fh->pos = 0; - file_loadfile2(finfo->clustno, &fh->size, task->fat); + fh->buf = file_loadfile2(finfo->clustno, &fh->size, task->fat); } } } else if (edx == 22) { @@ -644,7 +642,7 @@ int *inthandler0c(int *esp) cons_putstr0(cons, "\nINT 0C :\n Stack Exception.\n"); sprintf(s, "EIP = %08X\n", esp[11]); cons_putstr0(cons, s); - return &(task->tss.esp0); /*强制结束程序*/ + return &(task->tss.esp0); /* �ُ�I�������� */ } int *inthandler0d(int *esp) @@ -655,7 +653,7 @@ int *inthandler0d(int *esp) cons_putstr0(cons, "\nINT 0D :\n General Protected Exception.\n"); sprintf(s, "EIP = %08X\n", esp[11]); cons_putstr0(cons, s); - return &(task->tss.esp0); /*强制结束程序*/ + return &(task->tss.esp0); /* �ُ�I�������� */ } void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col) diff --git a/30_day/haribote/haribote.sys b/30_day/haribote/haribote.sys deleted file mode 100644 index e098d2b2dc72ce95ff296ef38e8f320f59a0abbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33331 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 = 0; /* 等待鼠标的0xfa的阶段*/ -return; + return; } int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat) @@ -40,13 +40,15 @@ int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat) /* 等待鼠标的0xfa的阶段 */ if (dat == 0xfa) { mdec->phase = 1; - } + } return 0; } if (mdec->phase == 1) { /* 等待鼠标第一字节的阶段 */ - mdec->buf[0] = dat; - mdec->phase = 2; + if ((dat & 0xc8) == 0x08) { + mdec->buf[0] = dat; + mdec->phase = 2; + } return 0; } if (mdec->phase == 2) { @@ -67,7 +69,7 @@ int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat) } if ((mdec->buf[0] & 0x20) != 0) { mdec->y |= 0xffffff00; - } + } mdec->y = - mdec->y; /* 鼠标的y方向与画面符号相反 */ return 1; } diff --git a/30_day/haribote/mtask.c b/30_day/haribote/mtask.c index f67b935..14bb46e 100644 --- a/30_day/haribote/mtask.c +++ b/30_day/haribote/mtask.c @@ -1,4 +1,4 @@ -/* 多任务管理 */ +/* �}���`�^�X�N�֌W */ #include "bootpack.h" @@ -16,7 +16,7 @@ void task_add(struct TASK *task) struct TASKLEVEL *tl = &taskctl->level[task->level]; tl->tasks[tl->running] = task; tl->running++; - task->flags = 2; /*活动中*/ + task->flags = 2; /* ���쒆 */ return; } @@ -25,38 +25,39 @@ void task_remove(struct TASK *task) int i; struct TASKLEVEL *tl = &taskctl->level[task->level]; - /*寻找task所在的位置*/ + /* task���ǂ��ɂ��邩��T�� */ for (i = 0; i < tl->running; i++) { if (tl->tasks[i] == task) { - /*在这里 */ + /* �����ɂ��� */ break; } } tl->running--; if (i < tl->now) { - tl->now--; /*需要移动成员,要相应地处理 */ + tl->now--; /* �����̂ŁA��������킹�Ă��� */ } if (tl->now >= tl->running) { - /*如果now的值出现异常,则进行修正*/ + /* now���������Ȓl�ɂȂ��Ă�����A�C������ */ tl->now = 0; } - task->flags = 1; /* 休眠中 */ + task->flags = 1; /* �X���[�v�� */ - /* 移动 */ + /* ���炵 */ for (; i < tl->running; i++) { tl->tasks[i] = tl->tasks[i + 1]; } + return; } void task_switchsub(void) { int i; - /*寻找最上层的LEVEL */ + /* ��ԏ�̃��x����T�� */ for (i = 0; i < MAX_TASKLEVELS; i++) { if (taskctl->level[i].running > 0) { - break; /*找到了*/ + break; /* ���‚����� */ } } taskctl->now_lv = i; @@ -77,7 +78,6 @@ struct TASK *task_init(struct MEMMAN *memman) struct TASK *task, *idle; struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; - taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL)); for (i = 0; i < MAX_TASKS; i++) { taskctl->tasks0[i].flags = 0; @@ -92,11 +92,11 @@ struct TASK *task_init(struct MEMMAN *memman) } task = task_alloc(); - task->flags = 2; /*活动中标志*/ - task->priority = 2; /* 0.02秒*/ - task->level = 0; /*最高LEVEL */ + task->flags = 2; /* ���쒆�}�[�N */ + task->priority = 2; /* 0.02�b */ + task->level = 0; /* �ō����x�� */ task_add(task); - task_switchsub(); /* LEVEL 设置*/ + task_switchsub(); /* ���x���ݒ� */ load_tr(task->sel); task_timer = timer_alloc(); timer_settime(task_timer, task->priority); @@ -151,7 +151,8 @@ void task_run(struct TASK *task, int level, int priority) if (priority > 0) { task->priority = priority; } - if (task->flags == 2 && task->level != level) { + + if (task->flags == 2 && task->level != level) { /*改变活动中的LEVEL */ task_remove(task); /*这里执行之后flag的值会变为1,于是下面的if语句块也会被执行*/ } @@ -160,6 +161,7 @@ void task_run(struct TASK *task, int level, int priority) task->level = level; task_add(task); } + taskctl->lv_change = 1; /*下次任务切换时检查LEVEL */ return; } @@ -181,7 +183,6 @@ void task_sleep(struct TASK *task) return; } - void task_switch(void) { struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; diff --git a/30_day/haribote/tek.c b/30_day/haribote/tek.c index 4062dcc..a765a64 100644 --- a/30_day/haribote/tek.c +++ b/30_day/haribote/tek.c @@ -231,7 +231,7 @@ static int tek_decode2(int siz, UCHAR *p, UCHAR *q) if (dsiz > bsiz || (hed & 0x21) != 0x01) return 1; if (hed & 0x40) - tek_getnum_s7s(&p); + tek_getnum_s7s(&p); /* �I�v�V�������ւ̃|�C���^��ǂݔ�΂� */ st = tek_lzrestore_stk2(p1 - p, p, dsiz, q); } return st; @@ -278,7 +278,7 @@ static int tek_lzrestore_tek5(int srcsiz, UCHAR *src, int outsiz, UCHAR *outbuf) lp = pb; pb = wrksiz; } - wrksiz = 0x180 * sizeof (UINT32) + (0x840 + (0x300 << (lc + lp))) * sizeof (tek_TPRB); /* Å’á15KB, lc+lp=3‚È‚çA36KB */ + wrksiz = 0x180 * sizeof (UINT32) + (0x840 + (0x300 << (lc + lp))) * sizeof (tek_TPRB); /* �Œ�15KB, lc+lp=3�Ȃ�A36KB */ work = (int *) memman_alloc_4k((struct MEMMAN *) MEMMAN_ADDR, wrksiz); if (work == NULL) return -1; @@ -457,7 +457,7 @@ static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int p for (i = sizeof (struct tek_STR_PRB) / sizeof (tek_TPRB) + (0x300 << (lc + lp)) - 2; i >= 0; i--) ((tek_TPRB *) prb)[i] = 1 << 15; for (i = 0; i < 32; i++) { - rd->bm[i].lt = (i >= 4); + rd->bm[i].lt = (i >= 4); /* 0..3�͎����Ȃ� */ rd->bm[i].lt0 = (i < 24) ? 16 * 1024 : 8 * 1024; rd->bm[i].s &= 0; rd->bm[i].t = rd->bm[i].m = 5; @@ -466,7 +466,7 @@ static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int p if (stk) { rd->rmsk = -1 << 11; for (i = 0; i < 32; i++) - rd->bm[i].lt = 0; + rd->bm[i].lt = 0; /* �S�Ď����Ȃ� */ for (i = 0; i < 14; i++) rd->ptbm[i] = &rd->bm[0]; } else { @@ -493,7 +493,7 @@ static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int p rd->bm[22].t = 0; rd->bm[22].m = 1; prb->repg3 = 0xffff; if (flags == -2) { /* z1 */ - rd->bm[22].lt = 0; + rd->bm[22].lt = 0; /* repg3��lt��0�� */ for (i = 0; i < 14; i++) pt[i] = pt1[i]; } else { From febac10ebfb5dd7af2ecf60d4f23f95e3c301877 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 20 May 2016 14:49:26 +0800 Subject: [PATCH 69/83] =?UTF-8?q?IPL=E7=9A=84=E6=94=B9=E8=89=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 30_day/Makefile | 4 +- 30_day/app_make.txt | 4 +- 30_day/haribote/Makefile | 8 +- 30_day/haribote/ipl10.nas | 152 ++++++++++++++++++++++++++++++++++++++ 30_day/invader/invader.c | 16 +++- 5 files changed, 174 insertions(+), 10 deletions(-) create mode 100644 30_day/haribote/ipl10.nas diff --git a/30_day/Makefile b/30_day/Makefile index d54fa0c..a5cdf58 100644 --- a/30_day/Makefile +++ b/30_day/Makefile @@ -14,7 +14,7 @@ default : #文件生成规则 -haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ +haribote.img : haribote/ipl10.bin haribote/haribote.sys Makefile \ a/a.hrb hello3/hello3.hrb hello4/hello4.hrb hello5/hello5.hrb \ winhelo/winhelo.hrb winhelo2/winhelo2.hrb winhelo3/winhelo3.hrb \ star1/star1.hrb stars/stars.hrb stars2/stars2.hrb \ @@ -25,7 +25,7 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ notrec/notrec.hrb bball/bball.hrb invader/invader.hrb \ calc/calc.hrb tview/tview.hrb mmlplay/mmlplay.hrb gview/gview.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ - wbinimg src:haribote/ipl20.bin len:512 from:0 to:0 \ + wbinimg src:haribote/ipl10.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ copy from:haribote/jp.nas to:@: \ copy from:make.bat to:@: \ diff --git a/30_day/app_make.txt b/30_day/app_make.txt index b1e4436..f0c66f3 100644 --- a/30_day/app_make.txt +++ b/30_day/app_make.txt @@ -35,10 +35,10 @@ $(STDAPP).bim : $(APP).obj $(STDLIBPATH)stdlib.lib Makefile ../app_make.txt $(OBJ2BIM) @$(RULEFILE) out:$(APP).bim map:$(APP).map stack:$(STACK) \ $(APP).obj $(STDLIBPATH)stdlib.lib -haribote.img : ../haribote/ipl20.bin ../haribote/haribote.sys $(APP).hrb \ +haribote.img : ../haribote/ipl10.bin ../haribote/haribote.sys $(APP).hrb \ Makefile ../app_make.txt $(EDIMG) imgin:../../z_tools/fdimg0at.tek \ - wbinimg src:../haribote/ipl20.bin len:512 from:0 to:0 \ + wbinimg src:../haribote/ipl10.bin len:512 from:0 to:0 \ copy from:../haribote/haribote.sys to:@: \ copy from:$(APP).hrb to:@: \ copy from:../nihongo/nihongo.fnt to:@: \ diff --git a/30_day/haribote/Makefile b/30_day/haribote/Makefile index 6844a71..cb530a1 100644 --- a/30_day/haribote/Makefile +++ b/30_day/haribote/Makefile @@ -23,13 +23,13 @@ DEL = del #默认动作 default : - $(MAKE) ipl20.bin + $(MAKE) ipl10.bin $(MAKE) haribote.sys # 镜像文件生成 -ipl20.bin : ipl20.nas Makefile - $(NASK) ipl20.nas ipl20.bin ipl20.lst +ipl10.bin : ipl10.nas Makefile + $(NASK) ipl10.nas ipl10.bin ipl10.lst asmhead.bin : asmhead.nas Makefile $(NASK) asmhead.nas asmhead.bin asmhead.lst @@ -75,5 +75,5 @@ clean : src_only : $(MAKE) clean - -$(DEL) ipl20.bin + -$(DEL) ipl10.bin -$(DEL) haribote.sys diff --git a/30_day/haribote/ipl10.nas b/30_day/haribote/ipl10.nas new file mode 100644 index 0000000..134d0c2 --- /dev/null +++ b/30_day/haribote/ipl10.nas @@ -0,0 +1,152 @@ +; haribote-ipl +; TAB=4 + +CYLS EQU 10 ; 声明CYLS=10 + + ORG 0x7c00 ; 指明程序装载地址 + +; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code + + JMP entry + DB 0x90 + DB "HARIBOTE" ; 启动扇区名称(8字节) + DW 512 ; 每个扇区(sector)大小(必须512字节) + DB 1 ; 簇(cluster)大小(必须为1个扇区) + DW 1 ; FAT起始位置(一般为第一个扇区) + DB 2 ; FAT个数(必须为2) + DW 224 ; 根目录大小(一般为224项) + DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512) + DB 0xf0 ; 磁盘类型(必须为0xf0) + DW 9 ; FAT的长度(必9扇区) + DW 18 ; 一个磁道(track)有几个扇区(必须为18) + DW 2 ; 磁头数(必2) + DD 0 ; 不使用分区,必须是0 + DD 2880 ; 重写一次磁盘大小 + DB 0,0,0x29 ; 意义不明(固定) + DD 0xffffffff ; (可能是)卷标号码 + DB "HARIBOTEOS " ; 磁盘的名称(必须为11字?,不足填空格) + DB "FAT12 " ; 磁盘格式名称(必??8字?,不足填空格) + RESB 18 ; 先空出18字节 + +; 程序主体 + +entry: + MOV AX,0 ; 初始化寄存器 + MOV SS,AX + MOV SP,0x7c00 + MOV DS,AX + +; 读取磁盘 + + MOV AX,0x0820 + MOV ES,AX + MOV CH,0 ; 柱面0 + MOV DH,0 ; 磁头0 + MOV CL,2 ; 扇区2 + MOV BX,18*2*CYLS-1 ; 要读取的合计扇区数 + CALL readfast ; 告诉读取 + +; 读取完毕,跳转到haribote.sys执行! + MOV [0x0ff0],CH ; 记录IPL实际读取了多少内容 + JMP 0xc200 + +error: + MOV AX,0 + MOV ES,AX + MOV SI,msg +putloop: + MOV AL,[SI] + ADD SI,1 ; 给SI加1 + CMP AL,0 + JE fin + MOV AH,0x0e ; 显示一个文字 + MOV BX,15 ; 指定字符颜色 + INT 0x10 ; 调用显卡BIOS + JMP putloop +fin: + HLT ; 让CPU停止,等待指令 + JMP fin ; 无限循环 +msg: + DB 0x0a, 0x0a ; 换行两次 + DB "load error" + DB 0x0a ; 换行 + DB 0 + +readfast: ; 使用AL尽量一次性读取数据 从此开始 +; ES:读取地址, CH:柱面, DH:磁头, CL:扇区, BX:读取扇区数 + + MOV AX,ES ; < 通过ES计算AL的最大值 > + SHL AX,3 ; 将AX除以32,将结果存入AH(SHL是左移位指令) + AND AH,0x7f ; AH是AH除以128所得的余数(512*128=64K) + MOV AL,128 ; AL = 128 - AH; AH是AH除以128所得的余数(512*128=64K) + SUB AL,AH + + MOV AH,BL ; < 通过BX计算AL的最大值并存入AH > + CMP BH,0 ; if (BH != 0) { AH = 18; } + JE .skip1 + MOV AH,18 +.skip1: + CMP AL,AH ; if (AL > AH) { AL = AH; } + JBE .skip2 + MOV AL,AH +.skip2: + + MOV AH,19 ; < 通过CL计算AL的最大值并存入AH > + SUB AH,CL ; AH = 19 - CL; + CMP AL,AH ; if (AL > AH) { AL = AH; } + JBE .skip3 + MOV AL,AH +.skip3: + + PUSH BX + MOV SI,0 ; 计算失败次数的寄存器 +retry: + MOV AH,0x02 ; AH=0x02 : 读取磁盘 + MOV BX,0 + MOV DL,0x00 ; A盘 + PUSH ES + PUSH DX + PUSH CX + PUSH AX + INT 0x13 ; 调用磁盘BIOS + JNC next ; 没有出错的话则跳转至next + ADD SI,1 ; 将SI加1 + CMP SI,5 ; 将SI与5比较 + JAE error ; SI >= 5则跳转至error + MOV AH,0x00 + MOV DL,0x00 ; A盘 + INT 0x13 ; 驱动器重置 + POP AX + POP CX + POP DX + POP ES + JMP retry +next: + POP AX + POP CX + POP DX + POP BX ; 将ES的内容存入BX + SHR BX,5 ; 将BX由16字节为单位转换为512字节为单位 + MOV AH,0 + ADD BX,AX ; BX += AL; + SHL BX,5 ; 将BX由512字节为单位转换为16字节为单位 + MOV ES,BX ; 相当于EX += AL * 0x20; + POP BX + SUB BX,AX + JZ .ret + ADD CL,AL ; 将CL加上AL + CMP CL,18 ; 将CL与18比较 + JBE readfast ; CL <= 18则跳转至readfast + MOV CL,1 + ADD DH,1 + CMP DH,2 + JB readfast ; DH < 2则跳转至readfast + MOV DH,0 + ADD CH,1 + JMP readfast +.ret: + RET + + RESB 0x7dfe-$ ; 到0x7dfe为止用0x00填充的指令 + + DB 0x55, 0xaa diff --git a/30_day/invader/invader.c b/30_day/invader/invader.c index d26d3b1..f045093 100644 --- a/30_day/invader/invader.c +++ b/30_day/invader/invader.c @@ -1,9 +1,9 @@ -#include /* sprintf */ #include /* strlen */ #include "apilib.h" void putstr(int win, char *winbuf, int x, int y, int col, unsigned char *s); void wait(int i, int timer, char *keyflag); +void setdec8(char *s, int i); static unsigned char charset[16 * 8] = { @@ -171,7 +171,7 @@ void HariMain(void) /* hit ! */ score += point; point++; - sprintf(s, "%08d", score); + setdec8(s, score); putstr(win, winbuf, 10, 0, 7, s); if (high < score) { high = score; @@ -279,3 +279,15 @@ void wait(int i, int timer, char *keyflag) } return; } + +void setdec8(char *s, int i) +/*将i用十进制表示并存入s*/ +{ + int j; + for (j = 7; j >= 0; j--) { + s[j] = '0' + i % 10; + i /= 10; + } + s[8] = 0; + return; +} From c1778219135d4b895aabd96e029b9da9a8162df0 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 20 May 2016 14:56:29 +0800 Subject: [PATCH 70/83] =?UTF-8?q?=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 +++++ 27_day/apilib/apilib.lib | Bin 8966 -> 0 bytes 27_day/haribote/haribote.sys | Bin 33331 -> 0 bytes 28_day/apilib/apilib.lib | Bin 8966 -> 0 bytes 28_day/haribote/haribote.sys | Bin 33331 -> 0 bytes 29_day/apilib/apilib.lib | Bin 8966 -> 0 bytes 29_day/haribote/haribote.sys | Bin 33331 -> 0 bytes 30_day/gview/bmp.obj | Bin 4292 -> 0 bytes 8 files changed, 5 insertions(+) delete mode 100644 27_day/apilib/apilib.lib delete mode 100644 27_day/haribote/haribote.sys delete mode 100644 28_day/apilib/apilib.lib delete mode 100644 28_day/haribote/haribote.sys delete mode 100644 29_day/apilib/apilib.lib delete mode 100644 29_day/haribote/haribote.sys delete mode 100644 30_day/gview/bmp.obj diff --git a/.gitignore b/.gitignore index 8444cec..f939afe 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,6 @@ *.hrb +*.lst +*.obj +*.map +*.bim +*.hrb \ No newline at end of file diff --git a/27_day/apilib/apilib.lib b/27_day/apilib/apilib.lib deleted file mode 100644 index 29a8eeebd154eb753bb6d0e59a2125dff5d57df1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8966 zcmeI2&uv5w%5XY3zgzHW)jywS}zIi{^ zs~^`oyY){J*V10ed5ca-)fYK*TCxI?b?20d;e=|w_fW&6}na@=PnqsV7Bha zllH#Z`liuxcX5h4?T34frc-RR8rFkav)SI2z1`<~9n-YOXg6AxJnfiN-K{$VG#f3` zDeN}e-9hQDY27!!m6wTISd9m!{SkCHS})$E;`RZ|rK z#|@ljv<` zk{TKXJq@0(S4Kv|fTU3jLBsIt#Z#JokY1dkHm1RSlte+J&l|wuM!?oo)Fa?YdgWaq z5Jr@J91^)TiH%C^Mx_v|Uh=Q{?=)o4s((anyz1OXNffL8`Da^wa!*(bQavlP)H}#5 z_bQnc(ug!^#8=xvJ5)&zgy-*-cLjt;4X_o;1C=^a4ne2vx7mNteS+v*rZ%R-eUwB) z=hLk|d5(-{iSR5Fo)yBACOny5Gjo{`-413{)-&R#@Je)y7U@RHA0;cozPqG!{eMD< zcOXHjLX}Af!2ca!tG6Ds^wv0udn73()F@y8O#*o;b z_d>5k$H8&G?9V=eLYT<^1PVXU?+X7jr?#AXi()kkTw9nBbg=@*)j4->8D{hBcrR-3nB Wt<|Qd)cUcbwAxHvcu(R_7XJe03V>?> diff --git a/27_day/haribote/haribote.sys b/27_day/haribote/haribote.sys deleted file mode 100644 index e098d2b2dc72ce95ff296ef38e8f320f59a0abbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33331 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 Wt<|Qd)cUcbwAxHvcu(R_7XJe03V>?> diff --git a/28_day/haribote/haribote.sys b/28_day/haribote/haribote.sys deleted file mode 100644 index e098d2b2dc72ce95ff296ef38e8f320f59a0abbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33331 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 Wt<|Qd)cUcbwAxHvcu(R_7XJe03V>?> diff --git a/29_day/haribote/haribote.sys b/29_day/haribote/haribote.sys deleted file mode 100644 index e098d2b2dc72ce95ff296ef38e8f320f59a0abbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33331 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
      -iO|P(5qiOQDo0inOQi^a4J({pw zJ+{NL+54!ZW4A`h>4}Ha_=k-Inn7E^tevdW%-m*nx|5tv`X9`)u)0Ajtki>HJt-_L z7B`w7Zm@yo)iy_ug`*Lhk0>>=%U>#Hb><6()}rFLN40U2Rl{vw4EN$`Bat@P`Qjw3 zrwnV}6A0I74$Lo44oYT+!D1lS}2jIS)iD9I9{_r z^V%JhSyI(myw0Yn(@K(XyiThXauL%Wa)C|0z>@DogT+jdfY-K=*EZ8D&Ge!Kn(bXE zih(VPDLE`tQ^ks5oEO9GlEf;;l(S-(gcrkYA?L+_mx?iGvSOH;7sG8alNZBh+KS Date: Fri, 20 May 2016 15:16:20 +0800 Subject: [PATCH 71/83] Update README --- LICENSE.txt | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 47 +------------------------ 2 files changed, 99 insertions(+), 46 deletions(-) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..f2b10d6 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,98 @@ +川合堂许可协议-01 ver.1.0 + 2000.12.30 H.Kawai (川合秀实) + +0.概要 + + 通俗地说:“这是自由软件,使用前使用后都无须支付任何费用,可以自由使用,也可以 +复制、修改,以及用于商业目的,但是作者对软件的bug以及因此所造成的损失不负任何责 +任。” + + 为了保护软件使用者以及软件修改者、参考者的利益,即便作者将来为该软件中所使用的 +算法申请专利,也保证不会向使用者收取授权费用。 + +1.目的 + + 适用于本协议的软件,旨在为公众带来利益,以及为软件技术的进步做出贡献。 + +2.宗旨 + + 本协议并不代表作者放弃著作权(仅放弃独家复制发布的权利),使用者可以自由复制并 +再次发布本软件的一部分甚至全部内容。使用时无须支付任何费用,对本软件的解析、修改 +也无须支付任何费用。 + + 适用于本协议的软件,可以无条件地用作商业目的,甚至可以将软件直接有偿出售。 + + 对于以适用于本协议的软件的一部分或全部内容为基础,在此之上所开发的软件(下称“ +派生物”),可以赋予任何种类的许可协议。即,派生物的作者可以禁止对派生物进行复制, +也可以只允许派生物以有偿形式发布。派生物的著作权属于该派生物的生成者,适用于本协 +议的软件作者不会对其派生物主张著作权。 + + 在派生物的文档中,没有义务对原始软件的作者进行介绍,但这句话,理所当然地,不意 +味着禁止这一行为。 + + 在发布派生物时,没有义务取得原始软件作者的同意,但这句话,理所当然地,不意味着 +禁止这一行为。 + + 作者不对软件的质量作出任何保证,因此,由于使用本软件所造成的损害,或者没有达到 +所期望的结果,作者不负任何责任。 + + 对于适用于本协议的软件中所使用的技术,除了事先取得作者授权的人以外,禁止其他人 +对其申请专利。但如果附加了新的技术并生成了派生物,允许对于追加的部分申请专利。作 +者在将来有可能对软件中的技术申请专利,但保证不会向派生物以及软件的使用收取授权费 +用。本保证不仅适用于申请专利之前所生成的派生物,也适用于专利取得后所生成的派生物。 + + 将解析结果汇总并申请专利,需要事先取得作者的同意,但对于申请专利以外的行为,没 +有任何限制。 + +3.补充 + + 基本上,作者十分欢迎复制本软件。如果要表示对作者的感谢,请将本软件推荐给更多的 +人,并复制给他们使用。作者希望有更多的人使用本软件,因此对于复制的行为非常支持。 +除此之外,如果可以将使用后的感想发给作者,作者一定会感到更加高兴。 + + 对于本协议所授权的软件,仅修改著作权信息并再次发布的行为,本协议并没有禁止,而 +是作为派生物来处理。这并不是一个漏洞。因此,如果你认为有必要仅修改著作权信息并再 +次发布本软件,是完全可以这样做的。 + + 除了修复bug、增加新功能等修改行为以外,对于为代码添加注释增加易读性、对文档进行 +补充等,不会反映在编译产物及运行结果上的修改也同样欢迎。如果生成了这样的派生物, +欢迎和作者联系(但这并不是义务)。 + + 如果你有任何疑问,或者对于制作派生物方面感到缺少某些信息,可以向作者提问。但是, +受作者精力所限可能无法一一进行回复,请大家谅解。对于协议本身漏洞的指摘,请联系作 +者或川合堂。 + + 也许,对于本协议所授权的软件中所使用的技术,禁止未经作者允许申请专利这一点,和 +日本的专利法是向抵触的(希望大家提出自己的见解)。对此,最初提出本协议的川合秀实 +的见解如下。 + + 指定专利法的背景,是因为如果发明者为了保护自己发明所带来的利益,而拒绝将发明的 +详情公开,会阻碍科学技术的进步,因此在法律上对于其所公开的内容,在一定时间内给予 +独家使用的保护,这是专利法的精神所在。在本协议中,作者并没有故意隐藏发明的详细内 +容,因此即便禁止对其申请专利我认为也不违背专利法的精神。相反,不理解本协议精神的 +人,如果申请了专利并对原创的软件及派生物收取授权费用,这种担心反倒阻碍了科学技术 +的进步。因此,本协议的目的是事先消除这种担心,我认为和专利法是不抵触的。 + + 当然,最稳妥的做法是,作者对原创软件中可以被认作发明的全部内容申请并取得专利, +事前防止其他人来取得相关的专利,但是这对于作者来说负担很大。申请专利的负担和是否 +公开软件内容之间必须要有所取舍的话,可能有些人会放弃公开软件内容。这并不是专利法 +精神所期待的,也不符合我们的目的(参见“1.目的”)。 + + 此外,当发明的详细内容由于专利法的形式限制没有记述并明确的,由作者以外的人在未 +经许可的情况下将其解析并明确的行为,在本协议中是允许的。对于这部分内容,可以无偿 +公开,也可以有偿出售。 + + 不过,对于协议所授权的软件中的所有技术,并不能保证在使用时完全避免支付授权费用 +的可能性。如果在发布的时间点仍然有效的专利技术,在软件中被使用的话,该专利的所有 +者可以要求支付授权费用。本协议所保证的不收取专利授权费用,是针对软件内被认为是新 +发明的那一部分技术。 + + 如果需要将本协议适用于自己开发的软件,在事前事后均无须经过作者同意,可任意使用。 +如果有任何不方便之处,可以对协议文本进行修改。如需修改协议文本,为了避免歧义,请 +同时修改协议的名称。 + +4.链接 + + 川合堂URL http://www.imasy.org/~mone/kawaido/ + 川合秀实URL http://www.imasy.org/~kawai/ + e-mail kawai@imasy.org diff --git a/README.md b/README.md index 056a59d..bbe1796 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ 运行方法,在 `tolset` 中新建一个 `run` 文件夹,把代码拷贝进去,然后根据系统版本运行 `!cons_**.bat`。 -一般都是使用 `make run` 运行代码。可以直接看书。 +一般都是使用 `make run` 运行代码,27天开始使用 `make run_full`。可以直接看书。 ## 内容简介 @@ -49,51 +49,6 @@ 剩下的两天用来润色加工。这两天我们来做一些之前没来得及做,但做起来既简单又有趣的内容。 -## 川合堂许可协议 - -### 概要 - -通俗地说:“这是自由软件,使用前使用后都无须支付任何费用,可以自由使用,也可以 -复制、修改,以及用于商业目的,但是作者对软件的bug以及因此所造成的损失不负任何责 -任。” - -为了保护软件使用者以及软件修改者、参考者的利益,即便作者将来为该软件中所使用的 -算法申请专利,也保证不会向使用者收取授权费用。 - -### 目的 - -适用于本协议的软件,旨在为公众带来利益,以及为软件技术的进步做出贡献。 - -#### 宗旨 - -本协议并不代表作者放弃著作权(仅放弃独家复制发布的权利),使用者可以自由复制并 -再次发布本软件的一部分甚至全部内容。使用时无须支付任何费用,对本软件的解析、修改 -也无须支付任何费用。 - -适用于本协议的软件,可以无条件地用作商业目的,甚至可以将软件直接有偿出售。 - -对于以适用于本协议的软件的一部分或全部内容为基础,在此之上所开发的软件(下称“ -派生物”),可以赋予任何种类的许可协议。即,派生物的作者可以禁止对派生物进行复制, -也可以只允许派生物以有偿形式发布。派生物的著作权属于该派生物的生成者,适用于本协 -议的软件作者不会对其派生物主张著作权。 - -在派生物的文档中,没有义务对原始软件的作者进行介绍,但这句话,理所当然地,不意 -味着禁止这一行为。 - -在发布派生物时,没有义务取得原始软件作者的同意,但这句话,理所当然地,不意味着 -禁止这一行为。 - -作者不对软件的质量作出任何保证,因此,由于使用本软件所造成的损害,或者没有达到 -所期望的结果,作者不负任何责任。 - -对于适用于本协议的软件中所使用的技术,除了事先取得作者授权的人以外,禁止其他人 -对其申请专利。但如果附加了新的技术并生成了派生物,允许对于追加的部分申请专利。作 -者在将来有可能对软件中的技术申请专利,但保证不会向派生物以及软件的使用收取授权费 -用。本保证不仅适用于申请专利之前所生成的派生物,也适用于专利取得后所生成的派生物。 - -将解析结果汇总并申请专利,需要事先取得作者的同意,但对于申请专利以外的行为,没 -有任何限制。 - ### Links [川合堂](http://www.imasy.org/~mone/kawaido/) From 7c2fc6692785c1b53a6a38f7f20cfa9877e560a5 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 20 May 2016 15:28:31 +0800 Subject: [PATCH 72/83] add screen --- README.md | 4 ++++ Screen.png | Bin 0 -> 276709 bytes 2 files changed, 4 insertions(+) create mode 100644 Screen.png diff --git a/README.md b/README.md index bbe1796..cc624ad 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,10 @@ 一般都是使用 `make run` 运行代码,27天开始使用 `make run_full`。可以直接看书。 +## 完成效果 + +![Screen](Screen.png) + ## 内容简介 ### 第一周(第1天~第7天) diff --git a/Screen.png b/Screen.png new file mode 100644 index 0000000000000000000000000000000000000000..b964126c0604d4d8ac31c4c09fd232800fe630af GIT binary patch literal 276709 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

      2kbZ^aR7TFe-Vi5v}j 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�rmI`_y$2hb1+gw9i5j*hW~z%_aedVOKS^MZ4yHr=h4Y;d zmR7O55d;^0eLik`==vSsD#@PDJx}@-L}RPzMT(mCw_;{T+APDKP+sVq?G!H$ZIY?f zIoW1t)rO(?XQ+ky-8)a%dpZc54UJ>E-b9Ig|} z%@{n)iJU^*-yaA5I<469u03Gw=`H=wes`N0MAqezqF80_eF^5{lV;zdFs9-7q<_Lw;y)v!c9k+XGenI z)1+wA-lecPv8mNcaUE3(_!17AZ|aBiOq`M_v4Y2dFupF)((;=#7RCH%_P%Z}8rfk4iQQHhW!sSvsARt?CS0HD?^#XBdgBE-tai@(E5PVHji*%x;g zyRYXD#&_ca$Xh{|8-!JyO^XW-oJk8Ckb?Q?RvpoY(cvPY1P(n`Akgc&AvjY<;VDyOnSfeI{g?Er<_dF zwb5Rr>QRi~R0a#KP@snFeE(Rq>;pkq+9C$~K%@Ee+LT#E!XUNT2WK+TwC0;yu98&+ znCtl?{NV`!t~{S+CLQ%rpLFAr`JFuOIKOir;=(X+)9=g7=0Y@0mfr(OuhoN7bja#~ zhMPG~Ce5$pr0j6&85(M?n{nMP=!v^lrP+kL&g5r9F(!$H;p0X-Y*VLbRptAl{VlQD zFXUizlh+AtY+S=|;VWn-k3Uis-SD|r!FOtD^w#hf*#9!YOPOTJsd##Ftj&2MOBsd=1L8zf< zvk^=KN8$L25yKNWwK_z=(A(Rw-70E1R+onz@k+o}Mlo2=`Y0>Sg-5dsG;x#r1ZjstoB4 z8tB-QDQq~zZ&)wprjrN1V%ZcX>v_66mt?+PNbiS)?1*5s#JM5yxfKZ}qsaY$TsOT$ z^+Z%gmfZEcb>k(5Cel|ECPa0tR+dN3YQ4eh&+h6gBblx@7(xH*B&@%?Ho zdP%Q5g|437%gttF9qh2ysA#=~t0^MNL1=Ukv952!&DFjPFZpS1SldJ0K2f82bU$-O zeG-U3K4SfdXP9Yzh0-)_^;Vzru0&ME&F!?-H)Ywewt1+m_N(WUli+;rh?EH?$w!8- z+PMU~$uc^OI*Yr#QF0dKEUTlX!5cM9N{&dzWa>sBk_Mw?=9t_IgFo7fJKxQu3IrUx ziOxxpi@mxQovQj~S?%!!Jmxp(7yNzZ8_zuW>aTj?c{wD-i-L*q(Ky|8V})m;OMvI#IG&~21CC9mA_gaK$5y%-zDpP!c($@usl{tCR zCCl~NID1JSqoN|N3a4+nbN$+>{0Vk`GG!NfjkB2LDCaC`{Ozy_APPBt`Hqla!fL7k zBFcsX@N2tRu8ez5>GSz#!A(?Yf*zN=q@vXp?$%b?DrnyfOKnfgdiH}g5W>-sdC9(Z z>#!+>mOja6C*bY=!L@<8D8U;E5fLe|xTTezBu&=o45vjxbk$t*X`;=RWl)ne(FDu7 z86v007V2)tR>joqGn-wW`!q4Cfx^x?t}lO;oC1;M-*23A?`>|DeQ<8@!v1RdU4VJ( zmc~RnOBd=bg}Z8Y^%rn!iJEn(QLEj@+b$${CK9AW5H~Np%w!9)VVZW`c9p8v$%jWB z61aU8J;cZTBhnUx+5Gvi<{{Y*Gh;+BSBz730nYzc=>dg8KMr#?e)6-Mkj8zrDB%>G z{S7lTC$N1JvI}}O4j=&%fcM;mg6HlMrN7PrH5^M`ukJ}E*LW*{o_kJ8VQ{zHQv6u^ z#I6J=e=_euPy4#b#s9`>XZ~6CYLKt@|`z>JMXf`I)~{j)#Vpfb>#4 z*VY^|SUZv`#Bp=5DwQ$l*t}y*-*!!i=MX{KG(+)C?lU!d#&?8L;-x+wubJ6wX_PN& zdYo5)3-X#na|K)DK^-O=1%M;Zyon>f6z7#X4!+#&pipS%8h0&x%CV%H zM=^B*-N{SPdAS((Rl6?3!YivDZw1f>29t3j7#}MR+6u$h`>AW*)q;_JpQ3ikHBK1U z+WEehG=jYTCK53cWA&P~q26DQzO)SQr+@U#w3aAOSJKVt2Dv2Y%PSpw8D%9uYBN3;$}$sFx~~o_4MO!`yqvHPP?ezbGJBklveg>C#aU6r>9X zNN-9H2$3G7MCrXZsnR>4gxEA2nKlW_&j@`v-i2%eedtwbMO8AoxC!W zOlIagpS9L|nN1!7)>X+-9&nb*ita-d?@7QkCqvU^!yuk4)8=`(pbq{e^Ru-%V;R#c=A->C;qE+7?G6Vk3FW zfbBsj%!*pL_si!Al{@b{K2rK|+b?L8eX?&zqiV4g&ny8UR2LPt`H7tt*2nVw9UF7LA_~#$*0Av zkt>Es1vaW=P!by4uI3G4@cDuD#JI{$$^vsAYDhxYsJHtnnAta_Z$SaIAxMm@@R4^) z3mCySx!<5@t)=P9d5dK7w;a_36TlO1GUVjFL=PQTsbwT20>7wMmm_ zoA=B5g}^5x)MUQzGU;3j2sJ2Xg#(K?sEV}HgLYM2Q}{|$Rb7%c3gaWW`$=Nv0s6fP z^t?3t3>Sz`?p}IdeuQppT!{h?wd7qLKbfk{W3&JL8%#o+&oY1Y>39JMYPMg6KS4!6 z@X7XqV+E}Uwe$_SBJHS>{{x3b6Mo*YAPXMPyec}Awe25YA3Nav!rQZf0VtVc0FP@{j7kBwxU44DQr~J02Qx%o$)#55((B`gq6`v=OrvUx%LIhv91@@{H zx=PTk;ztTv$coPrn(@&Em6$ErUlVgf=Vf?lYTfQ~IWasE z;!xRDYmDm^-M|%9%G{4^05Q;Q3;fBkSXbZ0#ge{ufzDhide_^-2xz?T>NtOnxze!aY zBN}%uV=+{5`#~U$1E8DUF}LfW7SoKV008FHXLP+nMkXNFfqbHeLY!^ets=>aUZzon{BCWuAu0vx_W^?=$^BsLIt0`C1g@*y?G!ZtPt)R{_T&GtH2S z`cZC;V(Fi4>YJwWo-$`7s1uFsv8z3(_e@p`e!nE8@fNV--u(l|5+Imk($O(}D~?qY zb*Zn9PBVdmTs3;BQ49HegJBtjtEcn3;o`?-L$=W)<+<`8@}dkJ8BNUeYMb8S8n`!8 zu+ClBt4kkNqX|FXR&;6My2N_~S8bSx&uIzYF_}YWRa6?2CLMlK-XyTW0 zp@|_b#q61&sl(ucq&<1NMy)bL#^&%jv3;r&jI43fOrDpeTDr$a0Xk=L)>eh<$#?sz zI+%AmYR7|Q2<@4OWXb(RFlycJoHE7Jn%~fs?Y(G1z}0osr>$xb&<1IJZ%3ynj-XuS z3FGQ#ghG+GfI{B|k=2m*bsdpu;}L$GJ~!KH;78!ov+z3l6(S@CbY^!NA+7f_Xieo^ z@Uf%Z*UV>s;DDYz#gf(p_isYsPVC=_q`oo-*R^?Qh5*kBSJZ}T>o6KjdiT%Gps|8a zJG@NUtC_TXh!=>dxyKtGr!SQ9)a;Yd>Mn5uC7{?Pjmf2v;T25#-l-uP8U>U#EX4Hs z()TTMwzkz8OI|T`6+uBp<hYqR9E+*7U%5e z5%IkKCD*Al#vL|#VvfmHtV7?;{emY33S&N+ z`2d{J1ARJn$?uX9%_z~VwwRElyUc{VSlgKKy`>k=)o}nWaVGP&94Nyk{+R-;qksLV7qXr@7_hhcK2T z$BOCvc%^D-AhS*gI|cAEz!h_Lu49!RxQu+1t&@efc2r#gS58J^6f@|g!*k=@yLI#r z9D&7yb+IoHhp%Q8UoR~jI_~;tqQwd$oXc1CG;_}%F(h-UYh0Ns?h*^DbHnh2)kOm$ zvW0Z3YOY_SKD@$**czfGVh(={ZnYep^_o5~*fkO!b-qKU>FmS@KFG}b==pdwsV%Ab z^-E-gr=6kE?$^c}1n*^S4(Ipe(8&qtvQ9Hxg!JPQfmBvRG7;5^vbSg}{#I%y|EDIk zl02*Mr_L!slzCCFg%`u%(n**moF_kK&hhNlZhp z8Pjx5&9tLsQ}xmJ2j+$vCDIN&g(3Ju>=RXYDD#q@O5R_L0vIO1N;aD_1kI~4yLto* zgNNmP*%v(6x1Q$9*Cbt@U!dnrm$dd*Qi~{n^Rm0jq171POkQS>hra+iS4K6FD_1H6 zec9OS>cAXu&)gbgyjs}YjDkg8-N&R{k)hu8cvXkfiz2@J3aF6g#5>%6d@{nBOkTa! z+}sq0`@9~7Co+872ZZ(hr()~>b{{q3f7sHHgLV-Ve$3z6hV`2m8=X6U`Qtc$;Q8g| zP8M<R<6$62AU3--U~o5>{zt3_lUL*KAKKyqzL#gXm}BChKufOXUr|ypE0-AKV8)aucU?kb zY$?z2`qr(~u0+o;=jg{m0cRe}JU{AMjEC8(UJ@X1BBdH64bYMAA}M9x<~&&Z7XpMg zD^WzUcI5l*(yx_=r}{LI^oFy2a%iE81sp<;E8UG9Me?xf?KV-NTNV(#j-u`>k z7Dz`Ykc2+CrSJ64U#Q{jLCN1=u>Hx`BA)!GK(kJ-2Ce$DycI}oLvz;&M)qI6otcg; z=O=lk#GAd!MlXMN_wTRUEP(lP-W2{#NxuyGkBm6w=x@Trf{D1V--ljz=~KRS<3NK= zTYUe!iQ^Sf_O~UW+`L1P97A3fy5EWA?*{0S4XKCsX`*rnxe`JXSLK+}m5~=rX8g^j z1l^As!q}}RE9hTYhYHc$=6w6^S?2YGm;|RU!sVZy9?&s&0Sg6#R{gY*3dltL^LwS7 z6j17el;$Jh>!>bdl^2uQ>ujx0X;5m*FJ0EU)y&r$(!ZRy^U`iNsyRq9dAd*#=JLHf zneqZP;CpQB)2HARcAbLdCfg|?yT^E~4G8H(XfszN8%{onhp7FNua-fp?>KQ9e)<7J z8i@0qcN(e5Wys+$6Q9(3LB;4#o zFH5{Ps9O3bLnx-_r)iO;$h;eDR1l#gt&D)Pq#H8YLIbx%;P;Oom?%V=T_hTPuhxYa z<1OWRXVYIM?Pubnnra}aH%?d$hTa^Hc{P}jP)nYxei$1q`kZJ?Ru#jB^9JV}g7bm! z;b5-z9t+O%8;kx9#*uT_44C!wBt-+3RZ6 zxV$v3Une0U^(ajZ7Efewj>`1U<|<90=u_dDXvo_BXdY1NB5QGY31|l}w$1x|UNLSg zIP;TYfX1Wyr(|o1q=$xpj!h~3i3Nom`^V3%@_>aDU|ov*g<|M|pELdNJbLs~lUg=G-uEhCc*NMb_R8@7z)#puPZPkL0bCVOGV-VjJVkL* z!14eDQ~CVYZ;&tG^$Y!_3?epw5Xg~IzfL)si7`N2r7pYATRYVMTIl4L2VqA1EgsO}dqN)w53m16(R$dw`vSlJz~IyZis_GddW6!geGT-ooAHrQ zU_oBw{JDR!7n=vMKu2BEA#*6FZb{EhFL@i0y*VTu;>}S?4$wa z6nvfi(y(84p+C>6eHk_Fkx!ASIQ`3UcL6fU`RU(Jx69GF|ITq(J&8Rk%e((u6O!`p zj3}d+-)`>r2O?aD)j%&fvgEh!q@ePo_N&Hy;Fr@vN;5VNw1fTK0pcFkblskZVedfMt(-py6+Jy#B*~B#+oF8I4#xC2AT1klOtDuPN@v_C-=M_7h$awR|dk zbI|XB1Yl0s8llK_4Ef)EVBnt;ISg(b%#ht8EisSJX8h?@zn~`0kxsx^<{#`J4*ix( ziSs~%1K`O6TG#&5QBk9Y_k|n8BJ?4HEL~{`xS2Q$z5fKP9e}wW0L8Ie@;Es6*kAgE zm-#23qkwB7Q?+6` zc#iR0jF+y@xg1r9Z8MLiPH8Fl(q8oc@6ZY!b~V;<_fVSpNa>2|Znh|He+TK|dW>R2 z^6|_UrChrdB9~b~{*i1Ob1A*rh#~45*W>3(MtjL0SM&`Z`lrdn9sNXTG|#f2pQjiF zrhtne7FS61U^NGWiwK&m6B7fQDhJQ3;}>kz%@Q&WUXwSh5}nNn+!~IU_Xj~}Y>&2a z4A}yvM|WbhZn{MsTnw7n(M$0ZPkEyJsng=bB$7b8CD%GtQ6VOxIVGTuB^Q#{-5iU6 zW4`avt5j|Rf%0I4R(s^G&b+8z^ck#a7W`CPEU*3KJgHCX!z1^FW=nPHIA3t!2~W zeMZq9D@_eHZJKK$n1t>}vcd2QxihV!r5_oystL>I@e$o*3m`g>u2Lq2w(?OAs}i3} z&}Wvr4r6su&^7$62vGodQNi~dCK`t{HYs<$7aJok%Ljk*s_I0S#_8UB`CC7PM;@#6 z7g7}{_Y39SSb1cE2rooN7HPo5ln5VzPR5t?^}}Ti*Zn9u*Gy$gZ77Rqjcm}a*4`HI5cXv?Df_xRi9 z5={o38Fxk1?r2qf{-FOLDLOet5SR{!#j96>(ui8$&15rwtk7KZHPWp1eJ>n5wc$-z zUXZpS#iz|~U6`6E)aC9f8l4I4e(2=K3sj1}uk)oET9K>s=S5Nnk8v5)dFR~Sb1>M- z;%0B{s106|GUk0q=Fn1HF&sxBtWKRVf8mROw@5MKsvJ#y!8oY2WgP&5hBmlHHf=I; zxsOhXaS;XPHCC4{X;y~12L-aLoM%(c^iB7_9Ny7MsqZeHgxibJy^VZnNzt@F+v0f0 z*;c+H0`CwTX_XwRCf`rbiDy-kUNwdvoaj%9(i>-rZ@&mv8xA6!Gcq(0YmBxyG9gS9tzI+-#0No$ z#6Xt7RJo5{7G)!Ra;s&+$-1El!S_bAWly{+p7(qPRLFuh@ooa&j1t+!iyBWRb3p zRPxc`?VS!hKW50b##F0P#i;L_*r5hJl63D?rVBQ{29klt<%43a(bu1BCT@$!vj)L{ zME*_xtIt73ZkGjy{lZZx@a916h~_0#EtmE4$_6@Ud{in-m+YB%W(2-x$_)J|NITO`1ywDzW&DBj z%D9Ou)|f}lt-4rcJcaw5MmWC618XqpM~7SlokbNvvU^WY44r`T|=$9c8PfwMXqsa7*x!Cv2z=G{c{ zNZCTXx*D{eg5rswsFl>#9Id~iY%lY8P2ft=<@SKYxtMz(6*s#g-RPu9~p3LnT*gn78rHFdd z7k7R+tJd)(iFp5V zG|e%iZ(Aw>KR(;g#i$|3;SB&jVjYmsU$v{}+G(~u{SZ+Vv zeZL|jo8j`~)E=tdn5fd~cTyOe!{;5akS+7Yg%-w@8QnW zB>5$0$}dK@JQ5&a#iQjMFWWl{ktwe7Z;0lw(k@CTYOI87aUTQU#EA$G&JUj#`#RZE-YZ?!nONXm=yUO&=I0*m&)ZZV zSTt#HDw^ydhT2JWgwE)h-}d7dtFNp@YFb;$z{tj}&SJ<1Y&nMeBRub{DUsG~xMnDI zg({D_w6s%xxgsfyTX$4F9?-&Q7B7L8pVyzoGaB8#ZE#o~XKU?xoYD14a) ztrRUb$S;~+;r%q4K1$>1gYesBM4Hcy)4e7M3zHp@pR#W1$u9AC)$_AHD{fzioTGjF(%wv*u~?K(}SqNeAJ@;R)n87%Ng3tQ+jeivl& zsDbCMUkYYojUPOaeGMiJD$3sPpn}Mo!JE-0bnKpb=*oh%;!5_`w)WLH;Wy>{r-$-H zXGm7NWQjUhY%A{9y*)t&(`*tDdXzb+f@9h?94z2qC=I_cJkn(a1XI`4+&$&AKE)2U zS&o!_PwA44x{_3v=wBiJacRWNw74t7JOx8li1j_nN?}+~9Vju0NJ%-X$*!I^A*2$w z)7~D8wW?00?1Ma4D^a6XRjvKBF4e}&p0=%CX(zk1)N-HSl2^*`a@o9>L4Nd6<4qk1 zgnu2IyqL63DS7e;q2;;h#52vtxz6n6YF<0g%N)vl_lnp@YZ~RQ2qv_DumJJ>UN-zu z|9RG#!AGtpuUBM>guWsg&GpG@9$1U>YC`91Vd+0`FwbP@eO}IvHtg@*oA6Qhb*q}g zcpEpe#2bG!P`Vpa`q|R|RTGECr{vn}6H2!=-zvPD?OW10b!tDloAT+~%7P5xO{z_fHc}C2Evl39Y^aspiw8xR^v+Z+t7hZ;=pagO@?+ff$P$}H zEjvV|S%0mc`kpQ&5!HM6>X34BMI_drA9m`YU0|jkmAk+CeC4LJ1{^(`rlo=)uJDu1gxo1v{hp zS#0U<;p*rm(DTudHruP>*-pf?MM>naIYcuG#qXBXUiBDo+G(0PkGEiqaNS$JkM^iu zWxNi(25DZ}oN9eJ({Yq$I_MU^i!WL;3bvXkAp*OSjZ&oC7OBS;=S1tOI3DPkt#_K! z0w&QQRy4T3f(FySi+E83#`P^+-)}z1NCPiWm>bv=GY-IyQ3SX$%H)Qr=^@SIyon$?{q`>REy zR4Z$hz*yjqVTP0*smf5Jq;umEFYWj+6{KsYc&z82aO#wCaGAeRQopW~y(4Lq`CODo zBXO!!Lt+|aZ8P1`S=fBSb-yD<^X277jig-6Y)>|kkF~3V#TDNaN^JOcc5M%jXtVoh z=2!}=x=^%1AX>o}bn6Bg?pxevp4UvqQTP%Ue9-xTQz&NOba=^9_e*)5ERKVYZ~9Pm z)m3jJRxie(>2;L!c2(;b>Trt>P&o`4dXJ&E4!%2RMlcggi&Y@cMeK~~1K$)yxYa&= zI~(Ti4sxsR*^+8e{T51nrp;R9m2v61W=gfa=D8n(Ry{C)p*E&D5$zm1X_OTonKbH( zOl1PrY1z3@BA3Z5&O~GE$+G;0syNjqw|=%i?3_+H%s;fPJj~Z=nUDpXG_%4^V>>=z z($`1lP^yBeYd~`qe z{jC$=6jSo?1c(fpS7hTDwT`vOt9~r;1sn8L$dz0+=mZM)TgjHX)I9JTkIEj%T-5)h zA2N6pyZ~NMU0GikAcCJ}k)`(t?D5rTLQ<&F%ek%32tTRG-=?qnYPL2zC%!k!XkG?TExGiWz`phs1Mx!5V?A(See5@VlKEZDwG}-6^0NnZBcvKWnuUbR2HMI-&-A*i z3@!PDaZ98^CVs5{fx{q*y8ZIVEZuSKu{oA(LRx+G;Uu)SZ46uH>(}jI>=+lTv`|SV z1$}T)?UiL|{W2Wq%aQJ3->|8kIkAsQ6+(=Lj4FA>Y$9TzOR7xZo0I79N6zF4^gU9V zN*I|IMZEIN$b{Va759Xn%+g+iKGQ99O0Zi6<*66dLP#*!{dVzDIP*wTh%sDg5&O~k zx}!G5!M)mdfob(gcgw&z>Rz|(^z5zinc|A!t3T$cxEhTuc8zH9 z6gpX-bO1$5duyVH4_Iv%tb+`E<;48dF;lX@|Jc@jVjOMzj{+et^5qe$Wjvwu8Vf0~-K=`1mbFP}hwcxFt+Yj^`Q^wLb=nWmS zu8BG?-n2B6U+20=H2)xb`fwS#%L~&397vZ^au}6W^N{S?AN{b)oC>=u+UVQ1SgF3# zVbkkUQoQLIxU32%i%)#&V;c@-OuG!Ch{IOySYncxLpVcv-(?563*Oqb)vfB73`)>Q zs7sm-DC4-SSiBR3zxXMD>S-4q=@Z6~3yw#mX#EQo756O%HS5b9j#j(FjfIcWsT&`s zRTZ`xoo{^}LU`%W1cX|14*=9Ty)rbfDicmqGCh=FFLn`$2@D3;FBvN55Ct_N>)BiM z-5Z-$wg$)&Kj;}IZ_Q>;9r`i(jb;(46_<-W-2cI^L0FhXv|L-fxU`fMWCIBCz>~s~ z<+E@Wb{OA>do^{2w%*3J-=rPB!e}AGy5U2DG^4ABH&b7l8iDlIi1ZFjN7$q4B;w`q z%j3i+`CkR2*sm+YEc+*~tuYh)s(h)!tgnGXWp7K<=RuSdjw%wDDf}I&HR`KOwSRhj zYM!==tH`_QOq7m98p(AfAj;0vb~#GxbtPe(ZRuy zt_P1qE{84r{ulgb3fFXB;^5%i(Pu^rc6J<9OH0{)@@>J&?x&3fm7Qnlr?+6qb?c@s zDq0elJm*{6=FcUZ7UmY7h+I&5qg`foQ+ig&-iVGW;sq5n%)%{Bt2B0po9Uy3w^Rz? zKFWBCyk)(K3heP>wW2RNdjCs}LOT}Yy>808rvKhY3{5W=ZYR1z2}(AqDEH(kd-T-z zmL}a$@mNlG;~mOW+zhgZun)3e=s7zx6?Ffm#8pBC4#alf`VSnDkV{~eak|#N1`B~& z3Z7@k9so|32Ff!^H)k#^N;736Cg>>TO65Z0vf~e&g3o_U{SW&e>d?BbH!`{;EKv-o zFt~Zt#jdHz`rnXuq4*PmHOO@c$pO2>UPqx6aM{g zUI{3?Ya9hN4?9l&4Z7dRSO?pG%=S8k#)tF4B*0;3L)7DNZO%Oxr|T!tKeK;gBiN+t zr_CJG+;$h*sCZWuC8HP`tw8S|OPv8^ezVVa4ytoevH+EReT=&wZhjS=KcdPP{6BsN3xcxs2zHO?w zflsUb3vT}pbMH9^-gXaUW509g&^qnF5vNel)xiUqt(EVl)<(C)jbk^G_w{NU<;pgM zsU)>FlLm2O2@VjkII=xaete3tly10TV`+m?RKCk#4m;6MA*y1*Gd72(s?^ z@T{G~C`PznI^}BDb%-o~M=2szs=^r`t$aS7`UFW*8fq;DWaSJ2$ql#N2h!!(Y_dgV zTA$W|##Ns>cJN`+Q&cjJCGEQX{z;jm(Xm*VZ4Bi6nvK5Bgs|p8qHVk;ZqmbBxS@3x zt?&#SOACV>wjtNxp;sB7y6~dg#52|{9nU3_v7>dcHQzU`MZAhkySpt{A)q(?ZzYuD zSYP4R1uGhCvk;uUJ6-=|GBA~IBo}yHe^u>HKk-o0;1+4@gGKb2(h?FI!y50NYqQ+S)U*Y&l>;fmWM*2)~XujLiy3$M0+-Gc{PHhDtJkp`*nP{ zT%`(q=&iOXsAr*!X-DH0+>}c(ILU6-l+D2}8i_u-^U+VR00`b0FzOr7R<%DYu=kjd74W-@;V~Y%eFBIK;`8R-28% zcf-2>Erg!ph{g?h_Jm$pi$EUy$%~uj4oS(KC$|*+*i}STe)GeUH;gDW!QULxlL`N^`@P$Y=VEuZk3>_aPA>%xi8qK+&JS zNV;&ur#ia@Xh68*O0yI5#!do9n--DOcyflkXo+fwS$q?Lq(oYShESp~jMb;v}mcAEeBe08P8I;nc zPGS@~d-_@T2IC4w1*OLLiGms;?8NQ2-%&yFh zu8?SD%Wl>LS}x+-IE@U)7V9^pEpPwoUm-!FC4#H(G-pOycN3>l+?pdzXt^|ynfod* zF@(AtPct0{go1QRLr*Kmd;Zd6vQu|{Au*iKJYu-^j=t|q#|Y1U##~t2Ct8;^LuZ$x z7c|LC`Za&@_#HlGi+PdOvYcSEj|99w{E zC#UgN^5JcGswAi~%wvqS#_t<)9PtYGQzy*;;{$Oqrvu?<*W`+MTZXmYN|26qzGHg) zfS6t%T%d_RY)ff5+-tEe=yBHZWAB_nuQq2i&pgzsp7hhJ7veiiopLntH0rlX&q|6P>>V;lL|>IP`u|K!~7B8CR8r9 z8-4FQcRmih9A{W2NmmaIjY+R6X0Z^8Wy8PO-TVIaYxZqCH=6m-%YDwr#YT4Lkxuwa zV}vK)eyeN$JNHHr)d_dhb9v9KqG)&i4@VxX81(~#GCr!X~WRv%u>7gMQ#5- z{iwBPcqER;9qtX_l)vuy%-_45|Ei^bbJ<@$Q>((!1o5w$|043?v#^p6I0>b;B!G3UCjn1}VgRnh`a*Nqk4Gh>f)=a|&kak|faErCNEbN==3rl_mcFaNFIq>~fYWV|o` zMo#K&{+scG?)A`)okdGLXl*3)?#iM(V_<;IJzRR|`#aFGKfN*!WLp5|S=G5jP9RrO z>c942-3t^<3a$QE&aHJ?IRT@#=UGgGI?{&l*Ea*ezf2deEU$|I{b_rVmVX*DI+}9a zLEK?@;`_G%+k|lbYaB+F2%3AIG;A30gNEhsdF4=P+}oQ!VrT~9Ww-zC#zJC4lcA}X*hV_v8a(cpdr+7GlpN5`@;PX9FDxTn9E3J>}!yD zT*o>6^bgw!NC419*ZSD<{7=UN%SGq^4vq(Zzww`sw6TB}|N--_H%l!4V zZFapA3xluPNvExnzQnbV%qx?=6AhvaFR?Yh1q5%!jyigYDSWJt4)Q!51j-R6`7>iB zjJpnZ&Pa`y`e~FzU$iM#H3a*pua~$( zHbNH(YNy-|@9f}tNf{{Ts%?N?L|YKUr5qK{f$;?X*oT6Z3)$&Ps}TJoor1Ca>aqCl zc-j#WW42xc5oGH`AhSD%cWq;^HdJLbbQ0zddH(Wc$FTwU9O=Zx}q!ygp&7n2>ia;{Iuw z`wQbCU}{wI4Ea#~i?CI)7L7N9GA0t?!>;xx{N)MMknQFTAMT?wIW&G9EV7jkT=9mz zBlLo4ZWEG&=u52j4X%H(KIa7U^S=jI-VUSNvAjZEgN~+6`0VsHnxiF+E zv!$$C&JoYFw!LLcWX3zUUYp6<)Lh?GizV|SA8@OADw|KPW%o$k$v7Lp`=cE+ ztE-R7zI`Y^6ji&QwxU{J9mE83f*UJe4EjX8-SSmk;D}rGQa>UyE*T75droCg zdi)BkAq?ZNzONgos{tv@Xd4*XEl~udeGV}_k@S_Yw=Y4X>u+mM-7{WYPPOgaSD5c# zKG`zmmpHYyg~jeMQ?y!IS0cNd-z>OgF|=Y8Drz53kRB-%SLEPCcRdreBloO)zrGj1=9i5r~iO!8$!t?CfdM*4Z0}Q{d;&>#2 zyq9TfXv_;m`-M8DCl@nX1TkYj%FrWTQ&WHZOvu4=qVH~pJu6N0WAU}8kYtkXC#1Py zh8pK=kSqmKZ&-M%pg;vy%pOVvmuk86?tNrd1VZ24JQN_KA4L6VG2mY&FF-Dv*7bJZ zECb5lj4Mqgv`51c-Jn-e{>DeQg4KK=6}n2TNuN6DQy!!l*ZiBs!ZT+u54G{Fu2K2~qoSC|LQn zmfa(aCeA7__BzHJ?3$_;G37N zrzg(`?R|E9HbvNVB;%LKE1!lYQw#Q7>Y8d~FqCJvg|Y_J4)W^!}As2TZ-4coGL7N`65}n;&T1T zp1a_vK&+0tW0iS61e(pF!z#Fr#)DrqwmV*zf@s7EWLn?8P0{SXjL>StJ~IQ^6-4j7 zi06LERs%PG`(WOTxd0-e>3%bU zc^O4`8&hD8VeT^-Mopq!{V%)d;57D{MtDnOvy4#>V_RI5fl=?~Af&UO(*kS569E@S zU$FoUG*LEo`Wl&VV_sdMF0d8qR;lggotII)_i<|?-{x`2gsl47JGu;=Xhw7TpP1CN z*TEaeNgC)`*%zM|;CQDvSB)9!o_@YN`N4eK=+vd0f@h6$um9jCdwN?+8_a1>!BKSA z4>7Q)9@e=jY44@$X9Nk;(B&X(cG6Z&&;qY{Xox-D+E{wFv9Qrl2ytB-kNi%b8hJKp zujj9REbp@X`mG`%S(UBXLmEkfc;b6MXG0I`h~!^ZnchNZ%-T+`K8h4iOC$-Kp%07{ zxXY#}6skO)W>V6_O&S7AcGy`V1?kl%H+y_2Ula(ouJ`Xdw0gNv+nHq&%re|;qWGCT zmL^F{%gRMw?xE}A4Z5Uv?%ZA6GLFet9!4$TLYUJ)+o~+pwqdYNRM#3>B$Li5!35F3 z>sUbfaG7+wCVX2X!#zD*_036?<$w`B>N{163`14(Z7@@9F%5IT40o7Ve4@S4x!H6J2rGC$TI#EjzNdyfaaGfT3+ z;-4y-Z6C<*%kOzR8>@Dz_Ib3h@6Yay#)X>If5V6-M4KrCHP{z{not(qe_BpeD422XBK@kCCN|Di90BxB!g@TGMOg zvO(`80{j?!ERPDVT40MyVp(}sV7Fq?d9H*P)lEEHwOSN0l)d`(lcENC5ZmbI*U=r) z=Dox>Ah6ym(T1t-Q9P^bXgn(6+{6c6AkjE>mxUM+yL$fxYshOA)xZyIj{U+l5^#t_ zw;6A9gc?S{(%RFzaLaAC z&bn4ZtVKD zl)Wj-+dHgcQIo;kc0|*&$YOny`G()P*}XP&-B$KG#c}JyRpZ8WG{sEHgM!6th7I#Q z3@gGb!<&N?q-r$R6>L+iNQZgeg$#6r0OL;@Sv!>GON@g+QW3Pfv#mC5tY7V1GrM&6 zCYd=OnaKcsGt{0wG(cEUf)^+B{WZZ*iz8U?A#UGSe%^j&oAgd2g(TEa{`F%=XGi`# zwT~R}gp+DvqIrCKHgqb5ZEhPIz zG$Eh6a+X?zXx1bYMJ#$#Iz7UR4J!(|84WVv**J)$W$sO0=~}p3*qqPA+7@p-xXeWr z>zi!sQzcCNaPhtV+rbx|@0Dm5A9sA+*T%s5CWcqF)_g&3^K5F3hsuq0k){pvu|r{T zNwz119#2Xb;;qiTHNPK{uX4Xe59Q{T=#=R;PliJv3j#0TIa2-7Q-xdGT4J&w$R3fj z8TC<1z=Ot)3jIF5>k%;$0-TX~gB*uL+C`MA`q~+9);2ZEI(W_2SNE9lFDx-FtNdoG zt&gP>_5dbM#VT)^@9h^T1uG6emBVtHz$Bo6u{!eQxtl0~g~g|??qHW!je6C=w&5?+^b)pW zf?t?B04Fo|>SJ?lgxjd4UR%6i)s9hOT2_ezM;=+BoYm`0@?mTL}2vQA~`JlaiAPLkpj0YRr&}tBzj{i{Mcc#wZbC zbtl>TM~4x$)2T{qIZDVErCZzT^E_Ivss^D`YVm0S6a6=J(lj1~z!Qxw#-oH6lgay` z06WRdB;2WJYFBF`^WjvY?I^cm#<`JwZXV6(q&sV3o`6!{A2?mSZkhT|ru`m#GeTu7 zcoY<==OImv7W==9;~mxgRH3MDyb~RHtELK%713%tTp`KWJmM$FU`1z^BP zH{;gpo}7$yQMNW(E`}mh>V??jo*9p%vHSVALi=TjrFCV)v)2f^FW(LKWU;r^G)(>= zm=@g;bD$rlf5??JM-Qpo&yRNS65u@Eh<;mO6K4~xea{X@ikJw)t9rCmRss27o&I75 zC}STk+pE{l=puhu2Uib|V5}(pJbXv_lXd>bvqg33$&07x;pg?3?IVIU&u|};6O+fi z%lD4JL2!yJgYTu}?`<2RbI79@jr&Rj29idKBgkBTBL zge=h_16j1~RcOZj1>d@?>{Um({@vXjzDh8j^O8)hH-nUAeY_rsg=Z-EfqZk?_64Z$ z;yTbO&_>_iL2}_`{S|4`);9gUjb3+}502v76OrerJ1BUQ5W01eML$Rdi3itGXC5%& zy0c`y7rAiwN_^u2r+VVT`N%;fr2B?B3B*&SWfI=$D5{2Zbk&C=1ehF!$&x$l4G!?) zmImld4uWZx_3Mf8G6_(IOl1#HIp>KY0p~3!CGv292TZBb2TnIccA2&NcEAOis zzUpM!Yg3s$1BZU%KGajv*00ywz-!AN(E_HpI>O)ln2(_I0y-Mh{^~MPd#R}H=GMk$ zWkHU5K3io0GlNfc)sAw;Rw=uH5!(+Ra215DA|KZ z<6`Pb`{*W6{o3L&18B&d5aX_Pp7gcHuuwluS$oOg6IcZ8@< z?q5_?Tz!<`YGJZZCiP7l+7|evw#jlr5bMK$3BgLKR1W4rG}o@8(BuPVY@J!CADIFt z1|89(?2sG-KIzm+db^RxDr6Uf{qtJkkJed+GTEPqGh}T-f0*ibr)@`F*gD^>Sm#&k zWx9tD<5#6ITH*|NIs^N@cmGw;Mk*5MLNbiL#)fmqS2?LEicp!w6rFlw@YeyuPM?ez z2DF+@;-KFmjYY{T*0eOI4=Y4T4;F@H*5{U1s&v06z|nttgaGvQ$_pv4U;4T{>fKn& zFMU0!0Sne`{-v*H%V;k60Q&mr!9vr5sI)@?WY}mj7jZ!e>sc+?{HQR!k<9wj9d2zM zYebMNncIw4rXV`8_^iOs+w0|59G@=VBc-n$Au_T)!nGKsugt_4ThpVd*(=s*m}n-? zR6aO!@}COG`%(mW=OY8;yXwc$G)xD27Eg3VQ@4Q$BzqA)Hg2Hv#7pC zd;??rRAnKY9Pez+$m4r!0Dj!hgh&dL5n$O@A(auJF(-Qva`Sg=bH=QT1!tAEb0-5PVU~0v}R(HUuVE9X$#xhQFwkX>Y@@N<#Bx7^UH<;bhvJ)hd3w1bQs*O z4jeu=D1#5(4i>N_03R{dr&kY#~|d1G}ele~MI2utX9n zpo=qP0EPznt&e1rREmM65kjR!Y5*Fc9BA-Y(p zT9ZC7>j;w+N4yBn89+Dk{{zPka(G1!B?DS1?4i~d&5YSeo5-CkD;d*1prdWuY_wVV z>Wjy@9%@4_?mR`?6gZ$*Q6J(XvyfF|;@eBRGMr587#(k_58l)l9BIH9&?^0TH0_%M znQp<+_#R(tj*9KMY4%{s?0r}QeT7#x3W##C2ds@>e&7UpZQWscG7m8W-5qy)baNp) zOsB(U{zF@5y2<^^QlaMEM$&OICE|G$waD|TxyuT(#m-5y9?`yvPg&Hh4e8sm{|vBr z!bFRug^mDIhPQvJjlEGiZ4D(){|PUJ&$I5u!<(P zseyZYji~Vix|u8#1Mr#t0fPU|^&D<+I$Zs) zi0IcX8E!kpW%qtJ!_NDk+mzO;-|d8rw^|^JPq21x5dE!VToQuMnZJXm36uE3_^>00 zyfW2K{d3ROc~x|WAPw#r@BhKudq*{~HeBDqhDz@pR6sfiLXaYeC{=pzYEXLb5{M#5 z2k8pZd+(ul2-15?=v8{?K_I?^_kGTD?)t9pUC;Vli$7d5nS^0-UDwRs`?o8?jrptI zCs1wuB+;$8`3%RQs^FDFIN$j196q3v3`{rncQs0j<2)^!_qeNkRdzJMpZY43eQ5m_ z@_EC5&hdsAiS6t-)C$p#>a?**QD_Se0C zhM1eXNx?@dyjnu z44qlO5qvRr>b2@u3lw*#+nGN#z83$Xc6LSg#^c*Jo3C9Bv1Sku#R-9cK2#}iW%E!Q z5`Q(^W*}6NyhD%k*`4`nM1?gbJ3>P--b!PKidezsDXoF@IIp;Dp;2DvL-{MrrqMFf z;AOKLphu{P?)i{&KbYg089}rO|CE5dd#~9?>;_P0VpEOkpQ-V`syOlx$bgwYjrt7P zM?9E`XB8)zECMYT4a~f|rsGPvTxPI?l$}M25-a0`+TUoE^nDLH1v(V^imy|3DKS(; zIVd{<9uQ{sryC+6S#z&}YJ$_heMx{T4nJ1dPkHqA2H{ocN3Kpo{Fm7&h&g~^lW4as zt5((hgo>U*8N5Vus*@f2@Wi3wVy3COyMC0}JrmE8nlt95YDzPHI_S;-M?YxZYz5i) zT;t=Jn&{&g;ff~7&AkWNNm>H(B`9%ADO2sWSC6j8le`D0s0jXZG1;iE;8fVHmyvP_ zj<`J|FTJb%9KyL_ZU6+sZb$p55F9~})>-jL48rM7bn!!mzvK|*Lo{>iEJ<3&l^sD0S2z;YVsFH#*2s$stGg>`wLoq*R%AdMiHR>)`dY5O%@iZ07!zl% zMpnY9p;mKs&-$b;D6fjtSkGzoA^9^ zB(d6#PY=S*ejvgniGldUQqhPZ1m~trvvNK6U*h;7C6qsuCZE0)p{sr@bA!La#uOR4 zGN}~}5+LeMaEQFMPQA3sTm@vs&+~KFoy_$^`=h*WQBj7{e!IUz&ml{#wx3utAoVd4 z{JCP7xYsc#DCEjEXc^?s#`!>sdOiuXCeAx*sS#TuP*e)8l(}F!I=H9Bk}t5Fm=W1@ zG=TjYu4325#3{=NhJFDqsb8QX*kSKGPv`CM7_53aXWkke%$LybF&XN7Y2{u($%{L5 zu1D0^g`JNhC^VMQ&x+A0xS=*AOx*euXjlR6qYZ&+_RHb%I*N&d-hFBx0$eHB8eq=k zU*8^qOXzU3-oBEKc?WuD%@BnGjzHP@uWuYprac{E@NAn-{&uNSHR}x-e6#SG5XY3` zWx_9~ik{{vn!2xaJG)v_)S5#GBf{R}pg^vjJuD7OW?dmRSf-!A!uLgIc9rtvsoWA` zAc`7wF8Q}#)HbnnztPN!=qs}Q6)OQ#9BIV<+MQhb&XE)2uZPPxotkOKPKFf(+?<(U z=k4BW`!5IRltrC!eQ?4R9_^JcUm9YFE}Q^52V?}5Z4IrQN@DZVW@v#gZ`(?k`*XrAX3Glg?!Ky#z2##v)vHNMw37(wmQb=cH`4A}1mb>SAh$D?3d z@#0g{Hl{sbX$KU7{7r37|K50Y`f*)D-*U+Pd!S{>oprsmJ{yDX*bUM_XD8#t`MdhP?ffpFOWU}G5n+qP#V23wQ> zO&Jx=b=iz^Cj6Jy9v&X_%L@d+fVnKvnQB^}1pc^F2uWZhFhiY9XL@Nf1l%o)c*gol za(^J>8H5RN%VgaOdHH*^FyFryHj_$R{zR3Ck0#vq!5zti7Kitj{GOJo6RN^O_$gC0 zLOl7h5NK=ef7)bLc(#2`X+B<_r8iZ7ewyE-kEIK(K26Ups?ucqSK`If+m{{^5H)HU zxYj8CWJb~ZJZRK@{pWm|e2J_X_`URkrO#Bs@s?lHLx3k_vATbmwl2rjFO+kZEoX_< zzj-#(FAac$)?O|Z0f*`;p}S5(GEZ;bf(N9}kveT^8t*)n@4*fG15H>~SJb>b&4fG`~Pj)JRwjP_%Tps(V(l%A&TCFQZYU3j%)_2{@id!0Ia4nd6JmCbYdd$gba|+m0+%BX+d1; zDl3C&LF}Oa@^kfMq>X7`^)UJ8;YXlQR=Y8z_}e+K)Mq7<2W;SSl81g)Kf2FDeu1Qk zxG<@|K#ag@#yAof2bD5m;!SAn@Y77#2|a+prNw?~WQTQrgiT~L{nW598Q?poNXJ^3 zTy#nvBi>8ALHl8Y?as)}iH)qS+A)EJ#yz(}k}KEY@wOpvDk9K2T}ej;BtvDw9*%&< z$VC)fPw*N7HR>@vDA-2Wr*6;pG5VRAWG}L zx1>KWCq=!$j-k2afQLE7QxgkeelAyJY=oL9rj2@Xzw?s$?6qn-sj^YN-A7LLP_mxC?DcP7MVYv(xrzl^!9Dk?MkDQ%T<>oWR zRSmUm94rbOp}~nXmSEevq30q>^Oh|B8*(j17Pos&XzY=EzCnz!qmtNJL?m=#sjDO+ zH>_>x!Pxr3sHNswuCcs~fFwTDi=D(@(ORrUdI@a3h>J8HK=zgGB#0k zj#C6yGX}_DFR(c&9q5xJ4^KyhJQ)IxzJKQOVd(W|51ZM#MY$tS82P3#NBo>>Ni2W1 z;bd2%m2TmEzMEybG5Bc(YDE=OgzHWQZ2uyO{ZGWx-5&V-upr)7NPY%b9Nm z)PVtWPaDsdV^so06#r^N(=stSTV3f4Alz)_c5ylG*J&B{%}$K{Tx&%UeKMhjdSzP* zdlOfM9mu*18NEi%(zVzu;!zjjBGt!{NNI-HT(^gXl@0La(&|{Cx7bOHPrLB3xk{XHtpnv^9h`;*X+rMJ+Yn=h0O zREutm$ZA=t(}}$mi7y`SQiy6DI+f=LLD&_>KaC?P_b8Fs^g{r_M~vAXp(LaE2{JrX z=*F;1gQ$g`i&)?St!qubNkVY2;^XJ0A@Vjnqpi|Hn3|yLL3hdu)W1)}oa#`%8E#%I zeUyiBQIB4t=w9pV8ld2e2pw^CiuxF~w-RFD5W1vW(8HSP@0<_W;It63)MVbB$)v92 z96hb6kne&YDtBgj4}p_FrI^G#V~mlDkt2bM^iaWJF)@+{k(;ZSWo!-(=9$gD-W$K*35~c{O%ugta};a^iNQGf%hx zNAu}0Rj8Rp=+M;;FOoC4o<;eJ;7|Km=((Wt>u(nB<{|Z^FOmh}wX1$skK3!juA8@8 ztt*9`W6eUpE|1>(Fm+8;W)=@!uD8eLUwpJ1@NPA2LNUwT`@k!v=OTCaZX?R&!IhZ1gNz5d zWuv=1i8Co>Npif*jgfSbW?}4=c%R^QUq9Y3`XsD-&q4y)gk~7ecDc#OGB^oDaDji$ zJH%q!a!b!;tZl6$9pzc4BlYsfB}m-knrFH85|8|5{g0Jo+mFdCb~7_d6CbK_lr7E< z&suef_dU*tM6#;|8zv5WuWj{~mU;LGN-$Y55mYLkDSn<%%0WGe7vIaVgUjaLYx+uw zh~#+kA&KUNfI=|W`>=C)6RAkeeE)Wp>+0Do!^->?P#*U60=Si)5xmkZGN$ekUf?6! zBuSDscW7p+5 zBSu*fugXlLY})-;RDonx{yo!Jy0VTCx8r0YsMWF8yA34vssnwbii-_HWno@-%?**n zsYnrq3CCT>&OW1l%^VY9bcf%k@Z1*@Bhp?T$6V(IZERmjaV$6_tV_=eXx#D00DsmG z9V^+4rgK*K#Jk7cvTq2A<6Oh9(I{HE%j;o`Rd%Mu#7aHz<$TM@I}61NpF$7wTK z%`4pW*)zSvum%l8>ri1v&5l>GObj10ImQ!Zw~9rK?N#GfWAtMlCyc8ttH^RWwj4Yh zb56#GidNKXj#ShLwFk|!eRUC&wPy|ZR2`xh9nxJQbG77VZ->uyW(VW9zd)T&cOFAD z-3ck0953?Ew;EK;aktX5tL!+w^;FjJ*OdTp&WPWId4p5!$C zQ^#rY$G*6o-t_LGON*2ZjUy;rIRZ&~A2 z9=0y(e^GF`D<$(_C7P8(%riJqPsA#HT;9ntoxQSqV2z37{OKaSGN~Y%28ia3xQvMo z`>d=6hh)k>lDDATkdQ;D`8YaiBp6amv@6b0V*pG&By*z|R<5n2y{ly+WIDRH(k4!f zOp!4Vd|F-`!wrF3`3IWtXLF&=({0$Z6Z@$S2HZCUf@?8Zv0(M0B=ck$9j{l`)$u%hM%y=&m4%EnUeC{si|mS| zfMfd)tlz|H`8evot$&N;c7l*b)ismOv)L(gTeH(Wg{60ry2|!1l^=n zwZ|0D$bvH0(C@QHLd^I2yz&9)cprJPnG4*-XMBhGp4kPr@8=wyHy86;M?|5L#NHC; z+?dc*_h8+o>L&j)CgX2iLKR>}rO@eEb=muCaGbXZT474P# z!lLq^x}V*-7WzxM+sF}O9HUtNU>b6F$E6yoxpDRSD zg&eM0YQEggNGufkVM1L03SF$|Gq*U`mhA6J+a3>3b-JG+^mN4HCu6D$YY#Xw-uVW5 z{ihJGv~CM2!p7Hk1PtWvRu)L4o6Ykms$67=o8_3(`jQ|oqFU^cJ&f57_`(EttK9Jw z-(&{5WkmEnvRM2;-eJXB*BWV#dAQ{7FLBjU#Rct(*kQVb2~*3&B)3~L+fig_$a3qb z>TNlHd@)Ug;*OwIKWO~~km_l87Ecp8XdxJ@=R@K=9ov=Pn??)mo{FMog^_Q{$WYw* z^o4jA0rxUW(+iSbI`@;n%ocbV3&Z;#a+9xcYHB!Ss%LI!HVLLGM;?Eh?N%Uk9@S~u zT3x+JWO4aHF3pm^jaLYsXTQ42jbe-JOHS#^3mgx7@B}Ioly7eG$P8SyeCm(L~mG zPa1d2VUfX8CRuIpHKuNHlLuFJn0Fy!I}WPSOHBpB z#w3iiy`koqcf{<=q_0NSIXZrWa5(kBH{{uNMc^Z@+U1Vxdsl$lm~oxhY&TA4tBEl^ zD|P1|>$`ed4*9(^-*Wb+9(DCh!sdZ{n*%M$9b8~a82fqhFOG|*yORIcUBF^0^*_>r zKwJX=V3=WV?wm&wqbRw+`wJBG@QiLt5*>Qs!*qJvE4vRnbmk4+J(8?BlK{gQ-5iWR z7&Ec8(pfZFaKXZ@=)ogMcLh8Ax`MK<$BTw0o$rG7i0^&i!RJ={T-R@FC>aaiJ56C+ z(EC{#)1RJcY;o*%VBs_)&7wAIa5LW1%!RZ38C#fcaH?3eJYDJ?TW!OSsV2l$zd)4O zD^R0x!HGS}swJ^-JfqpRRG4YcLWAcE^bsPT^>n1Z;py6$z*XL}K!WJwxHy~Foy+ml z--SVh9~Vx7>?HWlWzmHv!L|jy5`<-qV}h;~@{5&wtfL)=L&X-2j`?`(Jgl*NT>Ulb zNT2VD&9yccC&ifT=a@6Mq8USXE`%}7aD~p)vVkQdO~WW}dMi6jV3omkh{86tLeF&`Bf);?5d>|rKikCHp1AMT zIG8kA`@sAy4d`mh|8MLANtwOkR^ZzpEXvg4b%mp#BAl=-`-fV8FbmT4tJrh;cW)D1 zJec_n@&n)=3R|5#SGv1cS0bn9WzV#stO;7xgQ*pJRvX&(ZBCE#FwE_%?kP1Eq%_9- zS+<%HsWEB+ZPe3O6yP8rzU_+@8uMnxyn`_cs&+0UzBAuB7x+;SCrrx%FQK-z{ak+C zGZ4C-rdAm{HBTnX&>SmtbQ`eOf8<{`A*v{(JGT9_Xd|nRv030F>QRMxsG(7;7J_xYPW;f3rrSm-Yh&F;e3xwOZ^1^7g{ z>OGFd+Y>m)+FT4tdvT62clhd~Q1x*R+TqFTR$q6;VN0=JZT1G{iQ0F`F*U2zo`LmJ z^K*FS9O9+xZQ9{#)##mMo>9w9f|;?|tdbt`Dy!wmNqoOUY=pvA+!I- ztI!qCmuPulaYs|nun2fyDC*F>v9T&Co0K{w8+(R^@^(V!Jk-xd)HQwV%B4MPA~*K5 z@j9Z(i-!x@}f$T8{pRJCH zziNH#2DK2g4NI94MS5U#X4;E11wN>|1iyQCTgy+j0C9r_7?JVQXUBW)e8xkzJ8z_z z73q=3spcj6`aL%^Z<5Y#DNv-;%iI&d0Uk7$hktCOHHMn+v4w~;%<~bQKWap4f5Fn$ zlnkbohRn{)%mfPI!DIW#jV#uAlPM~F`%4tcJ94ER?C6KSEdFfjG`_bt8+uGf1Tb^3 zqy}fdK*A>{I_ULUqvV*%rV+OG6G)$WD_^;u;mYVOXokeg!Ldro8|Un3g4I&@&p#N+ z(5_!u_IWCiv=@n)zWl$g0l zJ#H{F8ap50>PB5u<;_@nYtIZMvu#TlZ=IjH*%)pEPsDjZrpwN%x5!L+c} zrh>mtTkKbCE3T7gsQY7F8~Z$j(oGwz){TDNa6cZqDi-|QJ`cd)R!7jwTa%yui;<$} zoT3QIhZYXZ#HhV0Q1V*LUyol?Yp4s7jZ+&lo-uQ&X_Si`+_*7B`leJy{$80}FL-ZC zmRcp^e+OPM{=e*?7};YS7OS@Q{dWBTYm+zG>s{cBPn59B_u?DKG`yqf^&AF`0frLe zcsFcx{0S42eXKH7c4EKiD`^*0=gh#YA;gUiI$47z;NIZ@c3U_jy4_VooHdb*O*D(o z3~?Rc%9~G|I;8+FWZDiPWFEZRM)aQh-GY}51)RJB+x#nAnDY@w-7>1&4IT4OT;%Sa zDp*(f+kf>kz%+g5XA_e7M8G>8|KI%#pPvb|_{UW}_F1~_?-KsIqa4=r_-kb%GjU|w zN@s~to%~~8_eXo&3&$FF^mRd9EZ| z^ku_4AiqFt!LZWMzdz*mf0*{j3iLc6GDSwG2mtY~U4%gX=Y>k&xg&)GTLog+J@7%D zaj0%p{*RY6@lHKVZ#&MCw*Wr(`)$-O5EKv^CQ+B4ANC{h+Jo)OEV1ptJP<+sn*ag~ zO`%OKiz>%}ml#zp`2Wo34$atr=B}JR_XzRog#cSFle?Fq^c428f-!%3Nv*D=_Bc5 zAd%xno+%1x+_=lksB>P<{C7Dh{8G+w^kG6ovn^Jpc{T%|W#+iBdJ%t@ z$U5PGdPmr@T#KA$i}(Uw`gf{N2YX?azuG{EM&h#JkvNBXV=#EW!9ss z)L7CKS^eROFOtBXI_G5w{$snJuGD{PRdB^F`%Jw2_{V!P0gr34-ypze5TN?uVnBRN zn9v57{qRNXO;X|D?f^d%?klg5_7Z)gUSA-7%chXaVvNTUA6W)~r&jf(;yyy(Nd(@j zQH1xcq=3xCum5mY_qThPt(y_~ESxHqLalrS$H!;-LtiaU_fjeK{FRjF>$L2{&WbnJ zs=n7~X`O1a%NY9EGUFxY)!XA!QK=o(nc;x&bLi^-LGFBwsLrRUmHbpf2V7KM;$eix ze)XOZJum-|tWpZ$7ZA>eaNgu|7717Kym@?Hp6;c`qR;qG{IiI}$uH)52Cl0+4ed_; ztcFCz&ksXLzY6rZ1~-uTZ4gTH^?hg#IlMXwG5>+X z-$E21UMylw!fQLP-dhGoJ=&||VLnwbptG-2h^Sbj?lr1*(I%;X<2@JtHAaD)U#xWk z+ceK`KW^dT{%|XU0fJz8s)bf=D2G+ozZvoB+Go|zQbwurV)pucuPgR+`~hGyUGi3P zS>-G(p857ZhE?%JGa>}+M=(jawqnP%N<;)sgn3X_732D}$&!9oiA6nR>W+Atq)mai zb-fX70tllClu6(*!fb~{gKD$*jXnM0j%x<514lp0%}~E2W}hctCRF9Ud$6bHoZmBR zbLt)Ma_}Qug-?_H`97D>SYe!z-GxbESoR_qj!X`IIa}5P;EJ=51=-FoIilXBIZ}tb zyh7vXQ1!s7sau~RT5Airg1;p4EFBz z>2@nuO=!$VgR*>*vkVX^P8YjO?~YORCoyx=vQOjY+a0aAkz~~V7Nl%!7VP{LoSzAA zZ!_N{Kc%a0j4KOafu91i+>=t>fNonc$#tyC>bvpaqM3~XXM)#1rY-hQVXw!S;cVU2 zFLD%p_uX#x57IetTvr}{!cU;sAULZeN~iWF$DocG^}d5XOD|pkqE>a)Rp91&rMT{H4fz?sFw5!gfPmTl#V zZ9K@_9}D14i3lW)#Z?tIPw2WFft$?w!*<2!gM_%DP(!fYZM>)pBH zJ`X>9zccSc*}ZQs=})t?zKw;&=Dj%JQdKZ4*N>33qXmIKhPbGq?9#%euus|;S+$h{ zKuc*q$pO>+PfzFL?kSK%_{!n&FOXz6Wk7v^@`J~p+&N{{wy~b-3AG0z8)}B|Ag+I7 zV2Q2M%NW2boA0b*x|bA6<`&Ex&A`9e0?M2$L_c|X1AK@#$#=$l*0dIyyX^7irdkPv z?dlz$FY|25BI1yJRH1164=0)EiTV)!m$AFHxs>zbjnGVLzrK%Zq7KXF0nQN5i_=KLs7xl%G#qw@wD?7<`R$os|>wO%WeX{Gf4*(p+ zIUUSFUbnTtBW;^OZo&U|`Hw5?2LC^pL4K?=z?Zf7DM0t-o@PGTmsPt>ftYRL1=cY@ zX^3lY*_3X=mx@!{H9zTq*Qy~;xw%s){XpEBoQEx))3?sTBUdj9#W_+f^^KE@*U6A9 z<)>~V>>(YdB=9s!{&bp$w?A>_)29bvyW(_wbnP9kN z&xf1N!eHB>FliHV$)%R2&0&)Zj*8;7IP7iUk(*#Kb}9J`@`Q=hyE{ps#zwY18E1#t zGl3}RGg2Q&rew|9VdMl)8;8=V&7^8Mvc5EYQx^+%H(s~3CDonhuhLoAyli;ZQP>-g zLJt@;g%;f_8B13JIw<@DoqIgtrD3uay2~G(ot3BcJ)t zm?r;p9|kzBY@l5^#cZJHlcJLK!42E0ao6g2Mcw6*qH;PVd()pU!XE^yx4eFtr=Ao> zD&KKjYf;FUw~mw-GRr-ne;yKh#dohXI7Vudf>$j zz*4u(+G^FI%4nmCQLNvgpRKCC^T=Y`V8NRbeFbZU;=2RZ$A%LfY)Qx^<(l%+HgG&kEXi%lTP)$OgMcwv zeC10BCDjIDqI?f3N5M6$N#18;5vzK)N-_AR5WjgbvJWJBJ z#Z*QdFN+RjRYdLQeT(<00lBnazCn&{EW}3CR)bglk~wvPRwLaeOjsJtg3%9J)P0i# zG%XhIjYKy@CjRJB{uX^o#k0IoCmn~87v?fLa{UFmnwD(r1YGXABSl$>b`>i_MU{^r zW9mPUePlQkqps>@9@WyTQrA+uuG|lNw(sE9bgS`!yXER*wl*xq=&mthkuGp&tI+r- zWnTz94U6m=Lr2ATLFXrvf-v@4a(*aFJ=^TYX*4C(^k!4trpD$)%U4MUZO$iPM zFF(J3ufm{5PUDq()>nLo@(P0`kK|yxusMQ?fvs&W1&qs$QnM^6Psl}PVMD`g@#Ff0 z=jl6EZ{hMhF(eSuHhWSblDoI6n<%M-dN;J3(L=}G9Bh4bu!kz~8bR?>_hV3Q7J}Pr zFELG$%`5KjXbg@kHM5pyM4md2_zC0Emgg!z4AqQM_oZ{Ns5u+EQ~nlneb4yf?O?sg zeBTQK%X7mgQK&BK*g=ElVMJM<16=5J)pf!(>PUfl{EN~3jNL}^-{+`l3fOmv_4bLqnU)|lZxUVZlE_8Cb_KyGl3=R(?3%l z+Fq`&7ZoqlHJ+8}p`TT&@V)k-a6Wddhz$?mX}o=TAbNA8&4^8<3H!s(5e9|JI;3CeOSC_iD}hH3jGyK`ZPx04c-xjRgPHu|gmOg5w)m0a zVpuZ1z7l+AtL|Xu-s0EQ2T7!rw3wW($U^PNU3&4@%pftso|Sv;8} zo$Pa!J^%JX$sYTev?dYbR+ztyQ z?pSmMykpjaFnV{#j<3#}?Uj_$pCZK)f?-=zg>Eb-_vH13UA39nyXid2=i>&CX2d#> zJmDW~iqc0b^4$vo@szH5^!dtRU;g?~W`&8Z=OBIe4+XD;Ub|>siZ<$&mmIIqrNst> zGx7?2NGCSaHOk=_d5(^wXrn@2yRwS?J$eqs`^DTnysZk3TCYc^m$VhWZOC*fWTdNW z=E=y*SIdw_BQ0dqn&RE@p6n48FS?6!l#g1Z!w$6@k0I0Y5hD z{1urieS&4I^)LH4)4j|J&L56>3j#PR*vIqhX|q%M?qbRfdo1Hlh6Wz`tYI~tp7+nr zPy?l{DU*|WhO%plWG~`)97s<=ch+50aJ~CYZWIdI`Thb?R6f=*sjZEl(;tKKrEJ8~ zeytj<7_axW(EpSYJHATwEcO|RzFhx^l4wZ?o@by(a)>0UIByg64wi0Xma751>kqx( zvyjlhNFXxuEM&dbVUW-6p8L*@?VD;VmuP(zr)vkCUtY#a<9jd(hc9v~n+0cU@MSH| zXR4Fg+X}2G6XbO2)f{vgp9g^*5>_K&X?wVoW2v8x%Tv`=gHP^0@-)!r=>BF#p(ZW6 zg$nlF8m)nt3nidMB(AvQ>BhB*@|F^Xi)$^SY-FEdM;am@OSaZp$EERY1qW7atIwE@ z4s&Jb*+Mbxt}D`=b`C76z_iK@T!M>CVd7ScXBUc#`F)E#mRJ+;j$$*Umh1&iJ9i3o z47qO*>y7ImieT!iDJ5vXf!1Ow15ASA-fBqWUGz8fhN~jJsIOm<&7PC_p5XWuq~_;5 zQGOW5lGurdnTrdI1bTImfDVD|%l7F{&TxNi&{bSvBdj%1;Sc_4biBSL8{yz3ka%3q zeCyWhjh2tZsDz_g#;%etA_D>)qsos0rZn?+MlHWZMOz%maK$QX#;nW6cuK-znr8cn z+UXNVLgo4ffdvvM-t~;a!y~3)&7;qFTwbVag~0@>w}I zVpcAVUtV-K1pLD=<~B?F3kv@+0gR&^wH0pbEPbs(&&3r_0F>m}1?%Q30zaq9Y|ZE?9FTYV!ovz;d2plXZ)NfQxDTP3oC)O zw(i~Vdu2viaeN>Y^QqWeh-L_A`B)H8VJMDUCD>%Ck*qcKmOcKSfF+*6o6p`lvhaAv zjPaQ7QS4KBG0IaPTqxWw!R9(v$llvVQ|$?Sdectg>rt~p|? zxrSHQCE}z&Y9Fol6Cib5i~9wN&jo_Xk{6A|6aUHyx%GeDWj}kA$zuq(*V9P`Ms=~J zCX7A|9SdtU0vbBZj)f;-3v_4KB=^bBR1z-IkIzr%HegQ2P;0FC&SJxrdI=R@@QC-Y zHsI?Ye`J$gfsUS~anpMf>DgZ06m~?hc<1>QeQMqGyKdj6t6@AgO9xLLw>E+>()m!0 zSTCm5IL4bpm3IEM#q9(1JpE}C!om~dKz+x!%ZvhYQIX6v_BhEn-RerG{e%rO8$kMn6C_@o00E`YhfShWCmL8)lj04y6Oenh!?FY!}Fe0Eeu7t|$G#UN;7 zoS<}F3G_+nt@+w2em;2ov%yvB!waJMj^p4xCrwQ49I?0*%%MPpci zJJBh6u^LCPT#K&{)ptJ0n(uRRS);V+&9r54(Kh)kxu7u#TmULSGmRqf{W05?MAtMe zi(Dkm&uulGvP%MarSJhhEU9sFEuh2003j{hm}~bJD2$O2Bb?@rJm@r`l(_R_maJ}q zyMiPYwfXL&#dv<6yTU&9Cvrzqag#YmngWrI*Ja*IEGXBD`bsOwhbC$^nd(_I&d-O+ zVjxQokX_%CJ!Im&0|CJ=P>zOlt|4aX7rn+Z%vaw%>tn^6F);cqFupH zXCY~w+3ltVrc9PKBiaiT_oYqJe}RaBr)L8<-P4~omZ3uv>Zt}>-l6+AyV*c{z$w>%Q`IT?UXrX{V{t8h zVdwrH?nfw3O2&R?Hi7~cX{NP?y*iC~IKOtz3?RjzB+juhZRw1{uW36nP7uag@ z$b@r;jP}Ps_MGre+ChdqbtgFo%RySfeK~CNo=WQ+)wwL@ySQBj^wNXqI?{5igJjY6 zW*jL<)`UlC83`P_SK<}QZGg8UZ19H=vEcn{F@(p)rjiRuM{~C^`B<`DKM4Wsz~1$a zxXGdslaVN$;bn`Av*$7W>B+ z&b7^0E%*nB3oSAcT0|IFNZi{48L4{$>h6tap9ap9@fu{1z^z5dEy2m6*M0$1vB!f2 z1Ncm`n9hZ)I?u&yOdxuxy$KzR$+F_|l33f;w#c=3=U12!)n&u5lIzYZIn+1S(>`A1 zT44Od>>(nU_>c(Cz&&r|X=T-3QTm&_P5GvQnvt!Hk!{nSQWajLRYH|gZl%G)#?|Ye z2A}5ON*UvvaRSc^vHg;Sm8Xq>myqnoc;nqs)AhBD_D;JmO<+Uycz}W7s8g^iJj5VVQ&i%+EP3A1CP9z1ge< z9+t`hWP3}7E^RMfy8jt)!n*EY%7Hde`KH4}D`0X^Poe-Wg8VbLZJj1yptQkG0RQ!b z!Y1cX5@v}Pnaii%W{IobXWa+heaFd%bIjXK>q2|k|AZw;A;P~1X>v1^Sf<+!pqPZPgHD6541Abyqp1FW%f@Dz(or zSfI7=_{|dOT}XSGCVr)ts9R<*O(Tif5Mt)_-e$uO1do(EwmSv?t!29x2z6P60JaT4 zhWKdq^Pxm1b60||t}l0Qrt4ZbzsC%%b!!M()h7e$BVe-@PeT0q27evq393S5EBFu2 z^ef7yv;*cfv*($fq|M@AS;U|XjVOo8F93|28)BBXWOrUZm0$qd02nfWH3SE+r(jT_ z$y-3gvK*K~h92&}!4vgooBit|Z4{1NsmW zC|6js>-ISrHL%wtV&K#a`0A!HGt@)g0=t9Pruf78E-p_;thdR}`{87CMs)k}l-irz znbZ$%Rqd=OER1=wBfvlJ4<|Q6u1sj(yvfhm;UiuG0@&jJ1igTg$89xSCh z&Hfm!DpOm=E*FUx&jXGU$qTU}{=Yd&i0;}HjN#*UG5;3Pz9S?C{u0st_}!(URKqU7 zb$h@3tl)RlIostAZ$>u?wY@Lt5aRI{9|(|i{%zaf>GxB9>@z#}Z+s?y2vv%nUX8Ll z{6GNvuiBdp7LcL-v-b91RIzAXga7z>dJ1_wKAupce!E(JJ4{~vJx>e>g$8zZRo^cV z{Qt8Nu%G<)6#>=~E*rb@|F}_DDPyN4yt49NggP&vxd?R@?SnF}xJ_NW!zC7c;`y}Q!F;_hv%LXHYwp5LP@WP`0uGuvVBp&2+#v@tWg zX<~PAsRa)OAtQH{zF-NePnntAdODvmO*2U1zjAH1hWIUnu}%ZILYhzt*VJIi2jQRv zsjDH!&8iw=eH9f!BD}IORXqp@j(r+wdors-1+VAJE8a%_J?)~?5o~eh;vX1?+w(s7 z-L4Pk;ScBe&_4~5?W*jhtBtH&Y(bdxy6{hBn3sXub+4R;v}kGO1fZc25dj0@j{FFm z@Z`GDVWfuHYvBw7>hkB6goCN>`-4}q9wy05lf)qVh#qsVst?UvNcM zj$-cP`jKpP0t}#tAGsmcOw)h!*>TEr`E-K}A-Ae*r(q?(8=(N#87ytd%yA(&rl2Ue z&_!}`ylv-67|SHtOKn4({&q=r<1^Q7NvBt5LPKse?xy^wCU0pt$#c9ipR`7|mf#(b zRY1S_u|q@ND18A2WT1NhG1Ihl9~iN|0qSk?kLiivbLltpbNCw)tPOz~wAKXN_9>kE z-|MvQ8Oqehsv*cjzg=g)UL|oqgQHc8tqcIP9PmE;hVV(YK}LiOhb>{MTbtA%S<)b(3d!HRnUCsgeBU z5D%tn?%9j79idlshs9N1?t2wcgeg7!E?vfUkYLJB;e6-j2rr@Lin8lAqmq&AB3p>} zJ&R!|D|-9f(NcTZu71pBx?Q|r_0eZR1-EC-cAQ!Pp|0=APE07P8-3F?rlby>jpmM; z&P5KLy7Ia+w8o0_Rd)B+Z6r1yZf_H{>k|cTC99#&eRN;Pq(xir1M=FPZa>%i!!(ZX zY&x~361?_b+%DyuXYYJkjdYmO#JBl9M7?MGDcNCydk$Fy3S*N_TA4@~DUF`d-?QIu&U_=MW=_?q zsq>2;O*O@SwmoZI>$>xBK0U@Yt$Ir}QVKAWv@T6gtS2uZQ3OkYKStbNDZC^st6FQD zT=|bvDejAH%rDHIZbMd)qn^E|x%~B=W59an9}cx?t8qHcM|1j)=gL#Br3eJH9r<; z({mO17C=sP`q>#5p!tG1oyZSHgmy-0|NMi&MB_fESTb4~?|r8Nm73uN3ypt5phtGE z%*bSvt=YfsM6H`*6enP8F;~&aA8U(+W|ifw^tsVB_CJm;GJ!ZaSbxq)I?;FxF|-Qr zSzI^4^|xSnws^40WD-GK9dYTSm#=Hq-1^!cr(>idAz6h&J}SG-^XTt)6%#V3Dl!&! zx}-5HW@#@&Dq20?HD?&cmAe=+r~DC%v2@op!e{8KALOrBUk^*! zKZbRIeF=ZhBkB{`?8XkVxr`lu`2%C0s4q<-F`b=9AFz$)8&<(caTW znnd+VynisdZ#-bIlj{dX>uYJEOTs6Rt{yh6<^>@giiMPGZstZW{5p<`lGRU?KI}u{ z0#B$o?{emXLyGu~)f~&tlM-nKG8G&^qI-MJThv&X*}wemVZxPH#A_O4p{wV5oB>J3cDD78b6`^ z#L+HI*Cu7Ba?cCJ1giBbcO(yIlp9y&;Yj>Br30dneA>Uem;Q5+E(UUyL}wxn{NKVm z{(W^(0n|dz|8E#ITK!{u^$9TWuG8BS;9L{y@A~7m>RX_B z5wneOzkY@7W&ezX6&hlLc%|NDEzgE=37=enb|FbOJSM{qD};}j47x=0!54N{Q#sk3 zn(w;C<)NsEL-A`>YApXICC%#r(T~oay*iIb8?H+xaz&A`LJElGy5U?Fn z#wR_uMRbN{MCEKs$F8zYLxs1Vt)E_~M{Mdb1wUk2#Qd&PrakKU+-E)ArZ9o=+3fyr z_?yuuk;N=Z_XxeihJ=OVul_o>%f+ECR3JGInjQUnm@=~IVj^YhDlV+QQ^-g8rfA;X zI=G{=fXMvV794o2!VcSlDZadO zkbuY88H*2cuwt7!@-&-%0CWEE7rr<11+S0msGq`;C{oiM>Xv+qzeG-H+ce^iFg5a$ z5m0ZWb+!MN@V0xUM)CJ6K0R|&>uF9{=b(+R%`59p7~jp&^PLr!CrSN5^z+&y(BbB- z(Ivvk9YeE-zE5^eY1QJZD_2YYqqWDoP|l!AMY-4nUugRzOo{^-f;0+F*KXTr)8j=< z{5?E!c`-Y0X7$mGO8k-Bd&t_OkG;VdR6P%qX%L31fO%M4xR_t=R+c%fk?_ytqnDw4 zHG*4=db;dZF~o0}gTB9w9t?-dEPYwH znrKakX_hDB#bHxxPJ;^>5AKumEe&d}a$kcB~htT(hy&gwo?e#{B1I!j< ztJHJ-@nM=g#gb%vED|+O!}bV6a~hn&pqP1}^u5pqu#HO6Ah`H|)aV%xm9skiTa9N3l;bB1zSi+WU@9XSH<1l-R8(a{J?}8yAd1JPa$Dn z0>u;YMTTC?KS}whwam0!A~&7;zPm?#Bze5a6@2n#4?_Q@^_7(+cyu8!J^(|Db<={H2;2+KCC(t3Svs0uH0!#9e?JENT{n%!}j}hNhE*~@(4^lr15jyCH{4c~psJvFG%sdE>16 z$w~f9Ze!9NP?xyB$->4h>H43sua-ZHCf7u1JukEvfP^DBKU`!}!dvl1ajW`ZN0vdc}*?RbA~jy$Xd}(Xs2%FPgg%kNfXO{|C#D zceB{)j6l+YL5}pM70)L+bzi#w0(@N#o^}6kV6T5cu>XI6uUO%WrrsA`S_=}Sr4T{+ zoFSz2H%DvaLP#N^veDcjv4iOl1u+lunW^G3 z&~dud04jGK?h$Axm4*xlk0c6YpM*bhK1dkM8#SB#AI1-a5eXM+dLj5;uVLp*xoqH9U4yn>wn4YX81l&PnF>8h%z&{uS67MSnA!{G%HBWa7O{?e?H|p)h?Y;f$8EX7l7evxVwH_3m1cRljQm!Y^7-KjiI|h)0a|XnPp}-~uW^rQ*$!L$ z=unh{`e9)g(&VVBlYYd?<#OYs*?PG_mad_2a{Tw9db00hQ@y6VY^g#&)5w4PWU!vh z={BKnCl+T5?0jU1(pxuBMeM?g42?(4ShJT@XAX1@T0QEZp^9w8vLvrob+L7f*irFe z-M>mhRJDWYI6fdoe% ze{4z4Ycyf>NVbg8CA0cYj>AB|v;JV;>yOvT_E!pPUW$V!i!xG2{xq~0RNQS1QxN)d zWFB~h_L-0E6rVs}mn{x78zse!VFfG=KvN-UN&YBQn*T7eptS zjhXL04iRPu@`GRUdr@yU>cwJFFm_S*TmCkj;pux&BPvsO|8k`X8i6U9;3wI2D$0F& zPN|_DCY+QWa-%b#F;bs7C>FO+%aN$GdSHj1R@9r#5lm2`X_h0^nMTkbb~S_nNErZX zc=a=cD(5cV%zNo577y6lSNstJlE}Uo>mw#X4@s#c`b))GB)SGEu7b=Ouk3!Knod); z;AryG$><$a1ke@m2(Z&~cSR)*y~TD-jtKXi--8{VRQxqDwGW4SyhZV@UL#d_ZY4>>?mkFu1Q60tI{$c9{#h$YL z9k=?$UCU95s`%$fT57TkMNe4aPHD_9tY-;NA{MA)QiYw`NjIF>RFDI`#)}aDex=7b z#R!=b4>#YZTJ4RYio=>sim|`2s+!Zk zDvtWHai?rwZhDRP^PPn(dbFN@Nyw9?-cH{&1M>OCShbxbtoyv*Ny5#S84@R4Q5@O3 zL6=YEL@h%%@3gYxn#vi~>Xh!ttt1j%a3hA)vlz<_$)c%ztCeZPQc;v%a9A*xp}L~1 znORJ3y~A=AGZ^h8R2}Y#sGx~HvB))~HDGP}krJjBv8ctJ$@lt9klf1Di{E!?*zV%t z(Vc?AWid(|38%ME5b5 zOHFz#RK}){s#<>+E-=ijD*j=LW=Of(Uh3IYJNva;Pz^q29Jm*Y zydU5Wj-p4GZxzGi;{59#ViSKt)CM~FkvNwj13TqFl+V5oLGtph4B9%;#ziP);k(e2 z5fIP#=A&}%Is*zlmNOTqd94S?)R}C9W9Aw>`9>%~13IBeo~WS{rQwv3CgaFWn!Rqj zhq7z0P97eqOY+*zh$<(mJ}KqVo@rI$QI*OTFZAmM+E^#;ufdy6;VEKqVGS`XRosjQ z1T=TLbFim~w~j|KRcY8D4r&%|TG;twfzPkE&#BcKA%ybC)L#FfY!(v?P^(QJx99ES z3^nB(vOhJbSY_&C#+l1!!clh--1Lt_wIN*QkyIpz&DR67(%{%tc~tdASTyvDuh%AT zbQj5X2huOB(0HGqTJoZ_M6q0CaUeU*m1mpByoHGTPLBDGJ;L%Mh=N%_*B+rW(B>50 z`Kl#d60iSjb`%&tr9z^TnknqdOu`Cy*ITcW2{+zgz;W~n@(x=SA48r}$|YeJRhE#O zwh*H9IZKqevHuKC;q zB!C^Lwfw=mt&q6VKeSHubV&|X>QXfhE;{&P%V&Efqo}p&4HLh6YpE-d0;0!@5#X#@ zAVUA?-GEN*^)pOVHtZj!c>vL!=)RBsZYh%<76=dGQ>%6Yt4(h6za~gm5J^>(B&(JZv4Kw>}H_Sf}f?; z0FwkxT%=BB>~Dpn)kD3n`mk;i{*|zAT;6EbqXf9>g*`G}^4~zuctjMd@&N#ZCP@qiu8+&iC#_Q($`oBV>KSbn=*1OZ_ ziVBoyOew{Wza(z3SeiiT;6;pWn2<;1)EDz8$dM)$(g?POFqaN%sLmbk>v+^VGS+|q zk9W`WaL;JAhtewkHdt932fNUIOcm&RF)I)#P!Xb+C$+H7i>SW}Gzl|iLM3mmk^Gt7 zFN8-Gj!VTCE``H9ZL4TDND#AzLycGKffB_ZxN47MHc1-%>4Xz(5qdN38BQogm=lq` zlqQiZLk5}G6(@|C2@}28cGQi7`FZ3={}e;c0k@9&uL`JD5sH5GYNuf>n8t2+%g7s> zmpgmqJ!6;2^QBQo3cRAWmcWteKQdJ@FG>iV?6GHtZ<}bGub&U{XR}cT#n?3zEc@1b z+*oce8yeSPDk_^x*iB}xeEP-svQWHJi{;RCmNY3B z0%C7s(CB(7M6*F(p`6h#0n8v$SkeuyqwURe;BJ z#Kdy%0*CJ^oE%-O4Szk9u-`J$85FC~xki4lu(7~JfNnkV>hwVK3S;|VhuDc8Eb%tM zwo$HX<{3riGesuk<;?^e@iPP&NG4hMw3j&g6@$V6i!b>~)ouE(f~|^5e-_J>Ms@^x9fBW z@Et>6j-;Hf;+D?${7WAu7m@X-^R~zf+|wH=q9xTkMT2`E-HpcVncgoDs}-vh#S@ZE zwD_z}_&2g=wr1whA**h#8~3oLxN(eY+?zg~Y4=L;tLjsu-5eW&N_go8FO}h{BAH#B zo7gJE9FuG8C#4ISI-I)Bld;OP1nbZ3>4O`<0l|=N%Ba>ZfCDmf$?xMX>`cY}`hF&5 zWdDezy-~_Bi)BhVjVl*Kwd`Hu_0*W<4F(kh%<^l++B5L0UsbQ_XLANRpBm^Lo7w+h z%tYm=5VzM9d~XP^3>>P1>smh1@Olo!QR#G1a(n1OC6TOsDzl~v`Ubu}a=iA~#}#e4 z%`-ff=?3!s0Uym<+Z8`*C^8uc%HsWjDxdP+bE!RF{KMdgp1fnN&$UC_B<~)h`{%$O z(wvUlgIQNjyqwfR&hx?Ql)wz__(aaKamr^HA;_%qsS zOl&1jYHxWooYd}nu?tQ{K#&RQZlf!T{>iCYM7#1v4haGhb@%B2y`*+}d7SLwRJcF? z+h^$5W}cT3oVq~4CuFSdX%KiIGRVZ+gqj~6T)5TzeE)XdeVkB(lv7cvyhydI`xn@B zsHVrqbYv&;`>r;|BN39G)VS#jC)|6QnJNj@&2i6by*ZDi6+zXu1>uje27gX)qRtZpMER|gmmOqw_WEKivh1Z0A3cMN_ zxk7vER;cU$&OlkWcsXleGXE5SqYk;-zvLRB%GFP`I_4kjmFntec}#zAjlyP`TS5`4 zJDx92KyMHgdY)DR_=PS1V7xE{G=wpY-->M!d(lS{E6TDpb0>a%=wfi;%Gehc*!Gn7 z=T$0%!n)JtC@HyKz5F*QP@8>Py#%YYyS{T9(BDf!6qQVQOL-->4L3D~xjkf$tocOw zI3G2+4Kt0p2%V2%<{&@x=vVhwvO^y2>VoeXsy?_mZIV!TE_qln28&Q^IsQ&KGMeAq z^Ut7D(!kNPHpnm`LP?(HY*>X2GLS;w0~@jx+Fmi<5Qn1E0#e&n4_M$q>dZLKd^vLr zm`XX^VRaQTO@UuYFm1;-5?n@ngckny46rI2u%e8%KD`becUi##92#NMhZpsQb~M41 zKJ&7Xc+7DM9ZfyB$aZReE&{qS%t;gjn%Ly13n7grt*-U&6$P$v0e?Gxkhj0t9pOEr z7z09TX3y_r`0Uy{18vl@0=NIr%~0=kc$o_sRYc9L^J4C2)6b@=5Q9b^M>!QprW-#x zS23mdWmq^nRVVwhd9*ij3SN`u_;J}kL_%_1Ez(aM`4C%K{8xm6fe1>SdyqaECd`uF zHwxTPQfMp1wwEh(WJCTUK-yPz^0j`$+Z2JS*E-C%eu<|!gXx~-HYLVT8>C|?PQ}zH zOV)UG=saGM9R9Bn(<$>Lrf;xlSEhhZ^V&TaWKskG93qPX9-|gnIq1Ar0u$80)?H4h zesw_m2a!sG&iD#Q;7ng?x;y+8_xayw?n?SGK0TU))xRV0vr0sIzO`c-Bi|2meK(xK z=!H;Q-2Y%KI(bOyysxXJsg3EGnm*{YZkyWZ&~{oiUh=KmJYFTkuYJbU(xUYplmOf@ z&=jfPq&LKY6ff{YF#z$LwCvmn`sN(bt0DXbuR3z9@0=F9ru_zYAMy_Y9)w;e@%-0g z|A8YlxV~DDW$UTAN|kj4?{URX%GQ|J%)tlNgWloz`QrnY9mZGT)bTId<4H#LexiJe zAfmFTgrN=oVZ8X+q%|{KKc^4~HxDe(luU%3d1igu=YC3ukl!_Zj&H}^DfAnYOP1Fb z_piUN7=qmJ?1whvjgE?K^D|`yN?GUzxLk1@Uc^?$R6N^4Q=ur)M~y!!U(@1Dm!VVN{rAA-% z`}(N@w@e#ax5Iy%i~pgo@&A*#T9|yR=X#spFMQYR$F>mACcv@?<)Qt@s zOzCeT>m^vnTeb|W0GOyh0H$AS_&A6`&zIq8A#rGE%0|b7ySGEU`A9eZDG_f{RMX3K z)1tR`<+T!4 zyQ|8!yyli`HqESKI5A}RMZCIUwzK}vpA(Ko8=PM2&xIt^m5xnq%QNbm0XQ&V^O%8sarrd1zvfdPyN%9a1OH^Mx zlTza?P?9={2NsBu!P(!7&Ud_cs3v6^{$0Ye5V@1d!4co^&OZ`+@O9iq57u$W!{m?Q zO;vODU4_F{CRnQHs*agO{9SDz{)abkkw%daH4f5}gG6eTRd*@lqn}kPZP3*WGehv% zLUWHwOfF`K>uBmKx{Fj;j?n2Z(xxO&)}Bt#kfT3hXS)s?K83|_<7NEqnY0(?zgaFI zk^DkES-M!cKY>=-ufAIlQ!pTpn+FqCJlAs>cqW%`GE;JCaZ{mqtBDkr9UYh<$#ptKZ z^nN{a2=LX<`J{GdwiP;AV%Kak?D~eCGKewH24f$a8xn8R1JN5Q3{0WvFFKu$8;{oR zfkS(8`(N{rJkjg_s}DAu9{jt7LwK|-fo^)W6Nxe@QBC+fm)rLCuEe$}{0G+XrE%DU z@w28KeeDb@7j<2PsuM(HLt^h*)}^+{1 z%DjO6ivM3?>p%W7R}5*9l*W&J__D=JFkFQ2*y3Mq5FPQOXnL*yGFHpCl2FSIpJ8&j zONQf;0Bg&;jPRSRE?n#@J4m@Aa0N?2z3ciP_4-+^^5fPl)=OY`!rvGbAKsYT$?+v+ z55LfK=Fi-E+F_tvZ4!^WBID>cOe$9|hiS?30sfdzsjQUl=lTrYXO>w5NbP4$fx`bTo zmf}LTYiCme(T5)!nzN2!v_tJfQQ%miJ|U%;5G`{`4lK5h7~y{Iz`nI-Ey9E#CN4s# z?OXM-p~Fn(5`raHS3N*B$AS2SYr_v*q97yCETy)v`WETlYF*Ivn|0*E)`{*mnr}IH zR+DWd_RW}G0ZEs@O?Ty1KND1TZ9(F`4b|a_=lbmb+>NvI6UQQ8ZZo+8vU&G)Scyf-XE;iydUWN z)8b{-+}WGzh|U)?ve92vk5e9pbC1u(TqnT60=tUIO1)*}Emj^{<`qAvU*>)`-H~{I z$_eij5@U#hN$Q{U>8nMID$|{d@D%DY;*(HGG_02gDsm=fXS@rW7^{bR(%6NPpDT{0 z8t>_kvg-tvYY8Rn`>my2#(vw(!s|~FNiPcWcrjPl@1jDj15#M=ViF<3mTvpw30}%9 zn!56JKB3m55mKyNZt(A>bkw8^k!gN5+%a`6}K&T+oqcfWuNzvyN}OX>haZ|F|^^P6Y{Cd zN`;v}H5p#vIE&oaZ-1TIie@(BfMhW@*c-3ypz;Swdr=YdVRK-cGOu%V`#51t4h5R= z&+5y%hNwP-RZPQmtwF;Tg_Q^GlBP_K&;ozbvIquBRukj&$0LRxQjGV~NO;UHMWz`H^nM`}UB>U&e9j~&uh-=_a5)3kgt^N~~z zo}$1g%@M0e0tJSgz^CyL&!gpBnSs4E62CWpvzeNwFS1Dcnd^dHXVVhbZOhzkHUFOS zJ4$|s37t&%h>eYRmotgfbVX<$RC%2!3Kw_mUGp@ZNg=X1`95WdMIKM^p3Iy`!BA|) zP^ym8l$?CX(!0pM{uC?LmNuUkX9ma7FJl!+7PXjOKUK`v*1#>_aaHlNLI!pF*Bi%e zDKDWK?6X7Zb+?Wl^jRYRDmd>-IB7 z8b7+7Jz`F#Az~TceTVBh_y&P3vCM$u$GUoulKnPJwmI=#`+M%-1Wt~VA=>+hyl}2) z5q8xLO{Vohn2NEL9_w+r9YXS zv1pUcj8Kdqw9#3wd%g}{kn&;oU9Hks?a%M`eaU^q4L8y@sQNERcuu)KDv&^lz`I@k zS(wUf5bq8dPXN1?BqNuNeCld@wiT znvcRgVgQ{5Rwyk$EIya{_M>hOjAMrtV3>a_S1@<|`Nqs7!w#j%ni$c6HF5A-ZS zI%PR8k0YV{?9Jq7vhbGD+3NRiKY>N6i$=A4C28-)ZBO;Aa2qvZ0Qc%&`@da7DD>7< zD3T#C(d2Zca(phB1{w?AQc&NfeARExs@?cBUJi?*2VX!W8Ieby_(^P_E07g=oK7WH&Z8!8-iQbExcF@lg4F zYMYYY>G1ue58|Wvfy~b1Eyi*Yd?sdee6Q=VOa~KROh$tnX7Wb!bj`=(3pHDsR?#3% zV&>uJerL5KM-KRbBAd_u_DkbRy;?ziJ?}QAI31X;Ew?{i`b+N{?Km}z|7sqhuFX%4 z*k;H5@HqSe&WOAtd~VNY???OVUcC@_n^7%O=FX6P^NcSES~JPg{yiW5c#L4AOixkU zsCeXT)rdvz#Mh{+vb{r$%KR1X505v8OCr)Q6QvD=nB;IZ=`Ru9cXauhC{EQl-mmeoBPORg4G4v?l z^UEh#fsEHjPc|rWE0s%779Xd7{7ug^Gp2}@6+z~k?Rh1vm=UEBeOC{iP{eiSe!$vb z>s}*58Q(ya{q3=@5v&DG#fN7pcOPpgTwb)tJRbTCz2WNO;VUcjdS@zd|M5U>_JmXX z(#HwtV&7!Ep2>YWTX95~s%ElZi7U3(BTb7E-8!0W^~@(9484C_w0w}_^+k3EK!p0y z8tDDXsrE%`6-T9ziOpPz_P$BTmIf+p^B)Y_KWlib1~C=!g#})C%<3HtN}`fu5x6$y za17gIomqmGu;Xe%sKII1fTS_QQ#)hY`Ip(#3RVRoZ5czb_VuL5P(<$G~S&q%A|_NW9sF}7!h(=JQWN&OMX}& zV|hCc%I~siT3a+mI1u;El=66s`Upz=#Ni+ zhK~DdW-FJ!y}Rc0_x5PpS?fxZQrvK~sB30_=iovb)QMsE?+_s|Pn=m50+qe+v4w)z z&hvZ2YtL6rVeZj|M2^e4BrV1mRPcfOKmP+d+|a_0=cB7a zft0J2-KkKl#h_IfG7MN`;1OZl8;tGRZh)%)gHa1aqB(GLUO3W4rvPy#Z43dBsnLfx zDJ`pUhOvJG)=nn3U;b~x)&31$`~N9mO`6UYNF2ChyYhP|6qY8a4(X&oU7MsToPJ95 zc5wmuzliB9=1FyN|MQpWy$9Ld5mUTTI=hyh%Jf({XChgbI%IIuX)sFCLVLy<^^GFv z=RvUwY*zR|TBUC0q+yA=$~=1l#4ChxOjHs3%6lht;)ul?Ob@ZtTR79`SlXBz0COrg z&fH5PALA{R6EKadvT4-Vs-nNAS`Cazsg6j9-nw@>B&ZgRnJZfIFlGNXG)j9gq~OFT zDvlmKy)0~!_@j}mY>=`#)t9ZD`mvBTL6MUgl6(e{RnmM#v9x=g*d-E|E~uSk1w_K_ z6*ajROuk0~HD%ilANe+v8&a^}`1P!NHCg3%7V&Aj(xbF}ZS~u@sfviS@zrcV~fUb<7DrU0^ z(d}=*1LMhUwTVaAu(Z5S`ksc6rOTh7V>~_`{xKGk`FK$x7q=jm?nO??X@l#)C(W8> zB_)CAyahInZ|6CLNDh(w`C6zD@Rh4iCvo4%d`~=zIo0 z(fI@JUX5r2jgSTPt+qt)=8?q!dl}1gJNd>64eR-O%F>aj7(r~xT~VZ5Oh0gs0;S-@ zet5}I&1F~nsdQa~C--^6s){`U{O6{3(fN0$NY-Amm(fhh30usRAK}x@($-L&hWh!7 z7+SdnVd=X4+vBVag~OxcDn~2yxDjvf74L4ZMbzOLHDhO_BEsq$Sw;Bsr&&@aNY*Hy zjd3*%BzU~eXkSrK45n>ua!h6h&b-APjC?CQLGZDq^eWm~YhlHe8C8kAXV z&l_r#`ppTbKLpbbbm3OzH3mT1KB;Oex1|xlIts7Cc2^D9&!&PCmBCk0wwu^b(hr2K zNMzH4HsrnmZI-a8i*J>WgaK2+dzWI{t4cc852Oc;)A~y*YXw6Grk-gom@-Gyf&#(B zER#%bk_&x!b8}|R$?Z-|H=}Rec5SD(`B`p(1ItOT_ILpp^o+}s8oiVrAPh@)3c6P$ z9Q2R6y~rkNL0Zc96G5mC3(+e%>Xc7Y=O;mK&tNkb`;MK{4tp)2rNgqE=H?_ts+(Aj zaaZ~9(ttsk!q?_bcC|2&R#sm1P`+9^NwIYqr<S zN6(HcoScq}61-2o=_tMuC28Ov2zsjNH5s-~&xCvud@t_iWWg-5*RQ^8U?+0U?58sS zUZ$U(&MeJRKp~Sd_G73e9;3|GWbsBL+na=e^@9;$`#~copq`|e@u|>GBePU3p4Ua@ zba5_;#^#TNWQMw)5tjK}}-Y;mOgfFk%9s^>=M z3VoBXr+<1#(Riu{IQD0A5tX#vgVR-zgF%c4>93k|ZB$3CQMa2+j?v1>51XDYqnFj?)gl4<%5w0&_!o}fLDx{2w+48_J4R32O& zn>(si0?#DP%DSmOg-7b7io2ELjC0sM*C-`D|3o)9+q26noUmK0p$|YR_&+YBas+HX1G3|o;>@!2PJLa|L zn`f2U$}I!6pyo;J`?sf|O@*jk1`NpY^f7Jun~F`?0(WeLw+pV3uHmq_p)yyiQGq?< zkGbN`6($Ziv9WD=zqP$>(KJ*YbuAc5tzqbE^c)*^GTyPWf+hYlHD4;&~-9cWLvewrwga3ETZGhUIwa&Gb* zS^H#|vai)++u{q#rQ)VF_^v2bc{bX4t&GUugI4sISE~v8ccD!)GqEkH@X_sBMCVHg zqZ%&6r&sEA%V|?67nD0+mRV3J0~Xw-C>+&%ECk0C#&hv1S(SZ~MYzb)gc~aVd|Gk* zPxjl>$w*ii(JExATNP*=_mC}!rqddLXp-AMmo%Q`o*fzw$?_%1A>UhJ4MFR%{i8h>MPLQ18OP;1vXyt&iA&dK2eQ5_z#|dhcA&&PS>_x(=ZLbn0YH5S~v77Xv zSMksC@ewg+h;^WBrl0q-TyITNT1wOvQ>~nm=!n9OjhjB6nNef^FE( znGxH{E6NEPpENE315R$_&ziST$rydH;Z>e2z*xFeYUgx!ae6@H6fZ;U_&EtWv*Dm0 z7J4cEyOTVFK&Kyp6PuH_FDg(7>sT$`d z5H0lzQY-`e)zB5PiqU!}7gXSPr_mWf|MYUjRAOx(ZCJ)i)PtWlKhDylJFgtaim)I3 zQU13Yfv1sk<$&@jxPR8zA(}0WeEj{o^>4vlXab@Y%ZgKQ1Y+d{NaT&AwsCEe3O;u8ZpMBB$hy zTl^BoEoD=9a-yj;nyk64$X*c1p4a*Ej_FDq{fze?4B;>6b^kkGlWPBZ-uuiPc+TA; z2+*4UFwc2L`oI4LcB~UI_PhYx^M8Oy7$~q2!&5_(Orn&#HlxvSprg;^ZyJV{$pM}F zH~6jPh(D+u`%T8=3}!9s{L~2>J`F`UA(Ym(5Q78_SJ@;PeLR1;>eL{ql*rY*_K#10 zDu2Kuv*bC?NG05zwW8F0_JJ#qu`IeFPmR4#vy>uik1C?&?0>)A~OG>3> zbcxd;R(;L8i6}RRi8F-KLF}|F3v7HCNxFF*inMA}m_nMP`w+|^v@Y=VivFse z_JO#;@Js)CRe?|i-5LvOj;ekPTLa)sYeQ=1ub2B&-p(gm*_0Ue)DEWFmngasG-Qk% zimy()z;x>lM=_|CAz?>)^yQ+x1`6(+;SQH zoz@s5v$oc@*?DU7lp|;c={8lczz0cS!X5A(Z+Z3jN9b3yQugIAK!8ep5)o`HrB%Be zXx=L0rE5lH|D!U$Ne{bX%_m$qO&9( zz8I?=Ny_-<@2H6#@9K%X)Kp!v(0W()_NJXX7c!&Uj*?w3H#uCxgGl$!Bd)_8N883( zTNh4IdE&IP$v@%*HfV<_qn<4=L18+6q;lvdZ>~ z-s3*4&Q?)Tdpt0sk3oxd`g#PlWmBqaZpt(B$jR@g3*8+CJ-7V}z|2j~roAe~mR{F< zj_jHHTP~IKtozoOS$fO#FUC(T(?L%trOeCCEU_P9yam*+K#7F&q3KQ@_~~)Qi;@Eh zI;?6(YDc`hhtmJDk@6qzFEvP-rX6QpQm_w^ zuph|%)^rMd5mv9%W;N+&t8?MX7T*fI%x zyTn>j+LH;c)#m-~VfO`pw8aibr%v_&g+$lN7OgbU+)oCImZAJ{4*$j;?3>1!Mc+W+ zlk0 z2B~6PhPJ5g%H%|QN0j};~6NZdsi0q6!XgF+RCNh9zjlLd24~;OiA2dGu?66RUKa}p>g~` zJa4#W=S3&nA71tp@slI|yR&?fm;;7;HwHe~gr~J(s7<#%nQB>%@CERGecu^W>;V1o zYneI#^ev*(5GQ(l`}H0la(K{D@K^P4F72Q|YQ(1}W#k8<&ue3UUko-%sqB1GH|)SG z2GDphit7>bUqNAi&)m*JyC+kgOE&KxiU@}aJW5jnkWdf7<7WXr$i-?lj2#_Cb8 z^XzE3X?1Hu>#+~6?T5p~?*2VaA~yf;Ut0{DKQf9+nx~x5R^1<7i76?KWj@;RWOj#( ze1p%u_GO{O6R&XiCVCm97@(uOoo` zYH|ebFmV1o{~7ZCCg`EdbQ^u@97*ZvAM{`TQ>ox>a7~e{Yg}$5tGr&NQs7j3*VxGV{9a1 zjqFw|o8Nd?k0jcE_!+r7eax1y2HKQy{&|F8S$?J)Kns~<0$e;@Ep-RMhS(oj$ZD1X zrOY^a6ap-EfT!AXAZtb1?fgk!bwKI5@1xy8b)@X&JtFvQl8>PU#x|Dtn7wl%SAGa{ z0;8LO-B5mF9Er8b8)(rm2Yv5&)oPR!pln@=Uvh=)k8k@Z0kf25X9~c)TY417)|2AR zp(M~hz}{JI*|l-)OQ=l^7Mr#UZUi)UU6-AMzh}B56Nstt@zdyyF|fu5r8NG*aKAGA zSJc$pVd0LDJ)LC=rsmEZiu|>sD3`R3-ti2eY~*i3iR?Zn+z5-ge}Sa!&-pE0#RYB7 z*0Zp+P*i`)O)5Hk#`$Q3*6Fdx#CU*gSA}p@MA^!I`sxbL@w`qjZA!>1-!*|F=dv!b z%%E@o7jy3w)KvJk{YIqnAb>mny^r4a+w;wP@XhRfkfTgyt*m+0z1DMI*ZsTd0E}$}swg}PXshRHV1rNH zZImI1H#5#muK_FI+(Ez1n?Ra+^)kKhLq4q!C_q#YuZj?&2YO|mbjUGKzlZ84es^9xk)almnigzG%ioprWyj3G z>c(^D+xxu`0Oym}`UWXH%lPu36Pm{z8oI71uHGDi$%?-L{6*QJ0t^CfL_>~51O@c5 zYAs|XD>ONxq8WD+gD89g`46GhBAsnHd&q&M?G;Te^{M`eRIize~pRc*@Bb%`ZY>N-gG8P#FrZz z=Un`Qh^II|OyQEBBy%s!A49M~s~rU>A^nA0=2Avwt@e-WsxBzGI*D3gL-s`7p=(NAZ{8KgipLty(0>51o@#`FaL_eQKbO`H=xpY0B^NKZ+v8KepRGkNuUFoX1`k_J;UZ=_M~f#^-yvjJ}SeMdp{? z60Q;3i;Fw0!;0FGN@0Vb|!Tl`!)3>EpBTOik|tlI_6@5)R$~>$rP3KB`uKobvvY`1^3w}uFAunKa%%bBOK6mU^^7;6 z%QKA@NYbBWk|Y{7-=NREnyK_;P>OZ#U#86w`;KmnOwte@g-rM84tPV=dSI#xZ{G;H z=1giHPhjfb1DH9Q14{%IXhD}%7(>$0BLwj%GwYNhW_yj<2TEZxHQN+@mqPv{xkvbp2Q7P75az7LzHai(1Y#R|V zT&MAI<)iF=&%fEkBVB9zxJ|^Jm-I!BiFT=_hoJ-{+viByJ6Ilk4h$qhH7VE5yw7v@ zbdgY#+wIC`q$88cKUH<>ksf>y4QA5l)hr6@pZ&h7k2japF|C1(*E?`js(eb^VlfeL zH-EGc49ka@|I)sndMO)y7^v;;ZdZX0`q5Tj-Q-Zny4O^dktjwp>-s^5wLe%h&GeJP zZl+L(c(#!4Jdg?{s9TFtpNz7Kid}*N}O1qDKJlet5gzUJDa&_FJGKp7nn7uMgXCJEYsk2 z>AgPZ{!oo(NeyYB(_v?^WxL%eb8WdcN80d34Aka??${FdW%Jb7c)=aP{~b-oCr zo7(H|)ex%OBj|b^SI~XLlVts;m^7u=qI8qjEZ^TRn0ePfb!SX_=`i`grEz8g zejy?u;L-IZTZuYz^O3}+{NZMnO2%H*}fNH!NP?tEUl>sV=#oVa3tqu;dSWP>i#o9=k-K-Zog!M{6mq2}>a zBeu7(abezRS3K=L(7k{yVjzXG^i#!G$z7%q1$5_TX9UyJ$zaB{O%y^L_YDt6(V06kuq&W)C>&(S}oHB6iK(0)d%6D6RhXtoXCn7`Ds&VetNy+`jY zX+hI^hHRvq*Q{=d1Y3H}#sAP|@I=s1ERtCDVwQ@mS)-jcSRU<*>YMiL!f*u8paEY?m$A?G^V&{WcXJ|jmU!lmgC*{FBCiac3 zOV-o^0<-gu!!=`k{cMrr$hWQK){N0A9G|%Wq+EXkn;wjXI^mbkAXi`c2TOtQUsP~! zR>Y#sMvVQP&|VicJ!sHc?;729Lr0czLf3Mu(X($>z74G)EhTzqTZv@XtaIY(4gA&R zz}#GrEZR&XjBc(14vE6*6DvcmWy8w3z$%6$m8r1vJSA+G*T0QulzvT`7+u4Q~ zb6V4hpL@PnQe9iod@@pF+k%w!&XkDHm(F>_nqL#+b$(!EIZ%dyK*5NZHqVV0{IG?; z2lhQk9 zjyvea{rR6YoZEM&{{X!eY$~Yu)F9i-#!G#9HKGH()-)cDSebHP3VDN_qa~#?xvnmG z!WjMjV761&-WNc2P?smn?9cLdqs(ze{$uswzV@Rnm5@P}*nT2DO8f^Mauqv)UryE5 z)falCwFiu{aOQ<9c_`E<-D7w-kUpP*EFO@NpQeQjxcz?`y-6PRC?l^Rh&O=4Yh} z-wSV-wS)_VhB`VUm?zL5-iTU=Y~y-$5g*~`Tv7S$!5aNgtKqxHlyb*zg=DmiXG$xG zRkR33IPg__gj(BzxT;3fR&x{Ue1K}jqvr^Al`2Z7D~7;PgRnohjpDe! zasFsC)4*D#8blA6t@{x#F6QO!@Pi)wLC|OA)Ucqh1Affg+seKM@nwY*W(BS zWs6Og-{ia#HEB!y1?+Cza?Fb|GT5@!v3btG;I&1se^xeNer5#X#!_~>u$c_hsW;>p z>09|0bmDr2f_{5P$E+Z~H;=QKy4(Z7KNg`!A1H*$T-F~9uswdQczg9td;!UG!`R6{;U2B(@J zS9eRf*?M&q9HNrFSTkXchtj>Lv=lNwr^t~!`3)_NH!(W3t&{i6%+Day#u{Xhr@hYz zJv|vNRa(7T<62E5R`@=uRc84LekWR~sPA_2WASdZuf;1?+VWJto&x?gc25?nfSLk($ zjrH5qJI;m~)z4OV&8Qg+Ne}TIv1g@9T{?0P?RnjoqqjCzpACrpp|krU#4&vV7V2iA zYq%eQ%bl4-dBqT#ERNw(9DHzc;6Gv>RnrE|MU!*xs9ehuK{Sj`ZMKCW%X@A38-{|F z0@&f$p&aHzbSiRse@4EE;M`FQF?41&dR}a3WbJW&BTz z{;s{EAuMhj&T#4bb!p(K(cXENyd}7myP~Z%ES^`+y7Z-MYvUwS{#i-VI z&la)yE1{2xw^f+=D9E)p4M{tDn3}PYar8INFt52bs<#M7Th2;kQ_cHLqQNcJ9O(vP z&1z?`7M`^jEs!=VQmsfy#ibf7tm2#7i8bdpW16nPPEVHWc$Ccae5`59aC9})-A#C< zD#cT2NBR4$XiAF}cZ-hdurAlgd%mx^Tfs4>aGlUVs#@xK-y0K4^QR_84)aW`Vj9kq ztMsI-JZ#e`G9yeZhAxKm0Vc!6h~f1%mZCpqpi^7;Y0~fx@*hAYbE~)Y;mS)nGG$Af z`Hy~s2C*JS%Zl91DX|jy{F={OQj(&I>`idKch=%> zt?5WEQ;}}t6=iCom+X7ADLey0^Zkb|y9R&${N9dE1=dNzLmMa$M$$s#2yc zxSPJa(i;+&-z3EGP~wbzTQkI(-w^yAtuGi)?b$u4>#n(zRHFH|$Z(ifm5WbHJH9d2 zj)(pG&$1GE(MykU?qM;VGObY_{ZNP23N@9Au{zB9ROy+%wm&On(> zzCZKZ=4k&Nu9k?Q=7#9aZu${5d&}ks4?Hzv6?)eU^B0yL>Yg2Rr`sLusI=sbi)vH( z@$PN``9qq*G(!urpjNkcLX-*YVWYxT-)L;@XZ&lBps@Kv?=1Vg8Z@+2-R_5p+3M7S?yA)9%wpJFHS)-2a{WCRa-Q-{!W#xdK6BX%k-+frR3yUiwFisOr zVH<4uo|(Y^A|K0o;3*Z=@`Km61Lxzv5C%GDoM^?q3mCdHMy$T1N9pucw)ovByyL z_4JUYx&z=*enbf*d$kAT2h5~k zJ8hnOULT$up!!6z7VCUoIO06rSzA1@41HY)392ZJC!)6z;MZ$(CI2qUV&|K--aQSM z7(JX|uk_5HHr_aQ2o`Hk+7Eh5n3psD51^K$Ql8(cf$TT_5c7>Q`b|$oiI%XT3$X8b z@R!h2j8Lr2w>D8&q~kC}*;sh2Ry~V&KB7rV1}0UIl9gg1WP4rELunInhonQ>ufBMh zn8Ke{^7FNfVLvLaXn497ovzE=!$_~GZglVt^{Nc5q5Hit+nv`$d>vup94|%WN++@2 z=pbTW&UjVE>&(41gPlaz?qL#`KMrKuAkp2P3)HnLa`=iw?oFxLS2tF{_S~8h`QsnA zcSkV*15zK?rrKle80%FLSGhE|uZlzsCpHixf5T_g&Y!EjqBzi2#z?gH$NdzK+FqS- zQ$RWlJ&n?mDcJz|Ba9XHphWeqfIyB;^ygAYy1DU~n*3yg%9K}`LqRz5W*@TA5Iufo zKX2?56J)d$SB{;WU$=|i8s#t{9YH6^Rw#M%SXBG;@$g|M%qFCGlvBGw(;VNQ$n1x>GMhjX(zMSWKJL1CCHNGW3(rAGD>?s>KlkdNlwGQkL9 zRThHA)B?2F*tg#cC$QG~86lU7rhG;=?VUF2{hr%vP7dMh z(N(L8zFGjuEF6l?XX1v}kld%@?Yw5VsfrXR{MNwtEsdscMNb~sJ*CWeS700?Eo(91 zDgCj4SnREKtPXetzX;&~myK2*TD}oaZvA$?lum1>z1#Bv_CDKTb?*D#OiBsz5;mMS z#G5qj;aGUBTOdJeMmp`46^GwjgEU4fonRYuo3umuwFzfIO;9Pi+RWDsyPBKR~ zsRTG*UC=jM{v3sA?XQ%A(5?_6*zEKNMs zbE+@CHocf9-wDmWXv^OTZsl`wx;ZY}jPun(3BqNUy#xx+T`1^_BMs5OS`x{ElPkw&H5|$#VC$+@dVA@c{`_p`TP%XbP?Qs zKiYZb0i}Z;60Wb^ks4GDYW#1%|3TXJ2Wv^@o4~4%jHtC+0a>(~?1mr~Oe2P&Ka@R< zy9;5yejEfFyPv`Y2cBHWwqQV#P$pk@v(IMCT;22zoeq4^1SbZ`nPtdZS7La1?a-@D z6Y~N8XcQUiX8~e<&9Crr7ZcgEM%48WrVTUZO|Y>pin)J{5Y61PP-kR}eoG5fs}k1| zWv@2t@-22qd#ap5Q8ZfN?L|Y2qXGMwBs``z9^8CS zUNJwQ3o*vVt?Z~-RJyX`t|*eJ6d(heSyl3N!`a^eP^3?9U)7n%zXYz4H>e@tq||21 zoZkdG6B&H3jEEOrUS<_Jx|eh6-j5}^xEuOx?Lyn2L@YVpeTTqIH zD&*n;jf=Xx#obl?JiRv>LzWmr>Zc~w~@6fzYk=MI2W{-KO(;Z?V8AC>4eEd@*}&<%u%k|b6&Z`%h;r7s&=3!$~~;h5t2>X&!5x6=F6>pg8Cd zI8E^fCqznQ^X^Y0dY!qib6-QxgKrAJtVi?li+u=3Ey*%Q4N>~uTu15F!07P{jENX9t)ulsuhkp;%2FRjS z1zZE;jMn(v{sFAvO=p|ue|xgKf@dTJkvyP5U}t^bXN=?l)-ol#p$Bo@fc0oZ(n#rQs|L=5-3I~ManPr zva+4Mbe#Y1&n<{Rs*&W~+}!E`b_%g7ou7IEq4AA?Di>9?3BBcYeY}iLILe`|!Km*W zxuVQEvCog4s5OQpaQwkxde-h8QcsBAMxk+|jwEk`PZsZ1X3qJZu?H%#7S*Oqa@q1~ zY*Ex~zsh<(?JB)VOqs5)UA?c~iH5w;-Omltn|506{+CIj7Ikr-N-6uqJ6lX)HgtGe zqjWFXv09woK$KtDY*DnuvhYRfCqP_iwGH5$bm?RZdMm`p+((z5S^({nD9>g)0x``) zo9f}6e~DyHB#GAQj9d_xojeO8*JhIR30TGPo(dKQzWt9ujZN_j=9wA%+FSKdPr9?w z!XPliYF4S|GNEpR4yh28w`>)!7;dAKqY*tIsfg}iCWx*J zNpUjccq5md?HV}1PkdgpATWAJF#82!7wm1P9QjCg0Lio90@U4@2)}>Wde%?|N4!$d z&kh*SiQ+2M&tL7nSB5Kar)5LidsY#gfa=LBur=eX`C8>3aQZ#273--^GnoNbOwaQ4QrDxGb~3ClXryB=0W zRG}Q#H1Eec(HfU0R0x%M=(2F|Kbcf>(ZoL1<#xCgp31TtBhJ&9la{2vRmDI&)ZnGPuHQFpX zdI7teoQXXxnss^VdaUWQRSxN2?Wn2zztcrtEH!jYxFGL265o_Gyw=R+b6G9&lYRc@ z>7ond({RqBI!_CV)nZ_e+u^aIwiEAbqO4vH}Gd|A_lj zB%iQ-s57;MdY)8yg-=wB0(JsY&5 zCoRT;Lz=G441l^W1cV>UnqZ@NBC%e&SSrOk@Rm#88JNUJl&H()hvKT#gR_vHdqZM( zGPdJ&(v3x8M$mlL0<46J2Vo2~ci;O8WZ6u0i@o8Bs}pf`QvJnk}|Q zkz47zxiEMuhsf6_D?9i>-~QtO+7FVsTM0f0yGPWkS8&ACBry1y#1#?tTbMx0UioZ2 zI$pn)*j<9{nk$C~HE{VK3%OJob}hJU(#Ev?;KV&8P%7M>@dZ3Hz_E_fZ} zR*F+|BG8nS(J%jHn&Y_la_?3eWODE`?Olds4d3Vb^+&PW*H*u9&u? zWu#(|UHig{kQI0bd$gjU#@WBx6B?_D3$WWdn*CQINA-s}^v&6-k+_e$I;@u=_zc&M za@%$=P*|{rsQP;^B1|(jK&UGgytE$^>&)o0Vp zh(zbAM7%v^EcX#!RmV+!hxNtaFL){`^q%-cF5U zC&H{Hsw_WFCBj63SkN{64LFCTUR|d zUE0fULFNGDK<%P95l7d%!AUvY_-iJ9Zgyg@&U0=|mTJs7;psSMc?%=G>D>_c&P!G^ zP%*SyJFc|EIDh_V@1XAN?;pRD@UZbLlKEWM;#Y7(=?}YdsA@oO31yB^8hPll8V&## z^MjesSi5CTh~LHPrR6XktE5b*z~`@&;vbVIv96+N{8e5(;AcpL)w>Wz`1^U&41n@D zFfTUp{8pN1%4d_$$RYgTL+#8~CLgV>b>zGC(mczUmWdSMXAbzsr?BHAPT9G=jZ|W( z+R)X+>u@f*(gkk|obTBuQ|70v)$_NnOC0j`>WVYQ4v2={Odl z-pvg@-(#Xb#X!vVO^v2cj(k0h+T6<<6Xmtk`wb|03}*eHf;7j>SOfm?Y zW@i#?bT|P%Pb$$_%JLf~PRUS|xP!WyZ>M#~KfpOCLaGtAL0PK3$yC&SS|DFayCi?eUw*_y_1S#YFEwIdBC<7f z#^L6>WM*2FX8_%6eoaNNY@mc zZ2{q0($%$}yGm>FZ@lPq{dL&uUeyTWr6@R-;S-Dsg#QB=F~%oUA{>3@k37j6+T-Mh zD5J^B@H`}wqH?G{ZGU}+mb*jtPM2%5%SGwF_n?}^)ee82LL*JfD7!9ww>CT(C^1VK zD=2{ovZ?rC8b^|y?;Mx$ke-|Eb*e6aIo)MuQs}tdNJgplVgDA9Nty8iWHvH%;^dW!1&s$|z1~r=iN{`p!ZYVW6R;p!R8-^!psWcx%7CBjW z#n;HNJPl|hn(X4Lq7#5_K%NO88i5s(VYs&Em8? zJ$m?#V8!i?EwJY#2_4bne;+N8(h!e2>Rvg7u&D~{;O;D2*(W9rj3i_+3z?@7wA?ZG zgJ{qr<@+~>*ldjNHec^r7xbKIe12%sD@}dch=s5y3I90K`q6W~5LM6Ut6ay#g7$RB zz0a}>F zCf{dF&T}^VemKA!>z$jJ{L^NdcYu6?Qp(yi=1HP|rJLX2bM|4xv6q^IJnuoq3;t+1 z&H7`2paoXJO}M$w+Z2lMZM8v$UbcqExj*DsE$6{;S9KR&*%XMWK7BtcBPxca5lnzL znJLk(n*%*}@&_6z;>-L~YwxS6&J)1~_%@z6cF(IaVD=kw!&Iz-5xrQfXC#*0b=TRe z+JI0q6i1Y)wbYkbYSfP~xY80f5sYSm+$6u8dFcE&YZ}n%+DL)DU8&$RH$`@4bDy!)uraP%VM=ZL+ z{Q^$8ivhhc8)G(JrY^r6{k;q5rP*u+=Sf`kkS!9XzaV3{Qn2=w&;8c)5fBVJ(AxKZhm>fF z=sHEHZLh7?zTU1UE~D%6u7763t3>^}M#1HgV`R-Z?}qzRU56QW|AQGPrg(*v`2wZj z7F--A?(XpSkV2ENX{L`VuBSre3vbJO#^#*EPCr`oM{+Zd%}`uT(?{|Evg`tc{Q4L#rwh^u;~QCl73gC+tM+on476btYG=i*=5`0r1G|#H zxmXzwBYF$^@+)(^E}-=Frn-|sBec$Fufsg?kvQHPLsM$jx`&!YdIM>~A_K?mT=Hn~ zoX4j*>EKPja{iOh=@DL{pu}-4#`wHUN{-aTrjGzTq)v!s_e`665xPpF8Ku}1Zd=pb z{xNude_r0OAU&XtokcSn_=B;wR0f9+lOv`#?KNg+lF*A}$@y&n5A*3iAL1{j)N^>N z*beogj4R~UJj4C92uvv37_Fn%Y@Ove=31zNp0&eW7X~*+2Oh{15zlz0BD1p_=2ziq zK;wLgg@_9C?$)4+@CIj8Jw2szx*@s23zhJ-3+vBkWNgxeUv`vFdvsCDia#CJ$OHs9 zvRzX1Tfz(jck!Rp_G|AX2|w7f?-!=zA@}rs>FE&5)!5voro`W4)ndO*;rC@!U#Z*0 z%v3%V@R0K1<*iwh@22Ej{d{erY0f@T*|$W7wi0I?@a|E9V_i72cf{lJJb7lWzZ#X( z-Lsd|un~^-ocMo$`A%Qh&P|5Xs1ga`?QIj}p%wJPUVV5=ZGD$)X;0``gyI2!Mf%U>SAivpU|@ zaJ+Ye-~xc91hFc;T)#fJ(AP-K(bq(lq93G2e*H2n z7`jfl3_`biZ!iY*zWfw>f4s+m@vQgB=g@^-MAk6Blz+|g)Plp~;U}D6r66TOtwIrL z`_(4j{mO;4o7)My=Y3dzc>}|n^3>GB3R~==BB~D#fqePZ`B)+W&kPx;I#)PzQsh^0 zH0`Zh7q6xjF7#C)iqLvsaBxwxX&BMU%=q#G78WS`b5FEs$?o*llrat#lBq1! z)07*dpKWwTU94*8&bQTg!#1gt&P@LST0Z=q&?SHVf<@!K}DVo)qh}={Ct(?r;uK{rd!+Rh)`&z6G`L7wn=|y~A+2RCOE?>%dV7i?Z|5MTad{#rE zGqR&?XxT%igb!%3)AJr4@Ol=8US0WJ>!;(^`Vg6@z!K9Ym0AKZ=Cmifrftqc{WCjP z=J*mLq+iU4=76~QORp>Jm&^ONMs(wsx3Phz?`^^f)}HqlKKcZBB^+4Nvu>xK*-q-$ zkrlL-djS))h=r;5$GQ6OsmlmR)XuL7T=;<2(WD#M<~?R)aJr*UGnE&7dxEiM8ee@f zHlqklqsAA1aWN!L1#jMaKo0KJl>3-5G_sf7)14~8xR5UX(th7cQ<3V*?o9aq z6RS#ZE}GjHyGl`>Td>>b%%^4I%txJv8b{`h&>~}FKXV5RSL#0ivuGdOH{~C|S9(Bt za1ehTOm!)HD~x~S{tqC}b+0QvasRg9p61bI^FKh|(|-WoOuK&ojt}?)l=_SR0H?p0 z8wTzOa<6q}WUqM>&>u;cx9&qVZc80*M@6?IW>?Y&j|f?!t{RjbT$6mDgQvPad|fZ%pN~2KIyRh zU0?F+sNvexRB!DA_D_=RZb+;&Mf?C`0-cQd2S`;H!wy*e{09gJ+*Qi{dGil2T#RjV z4Cy@RT7(>|+qOW#&{DL9CfcqHp^^YDg}l6R8gWv1L}-<qetXpzPq_QX^FMsn?%M&cxpa;xAyQ7h|(cDl8$052t_Y3>7416HAqIp9D49 z=Wu>V*H#Dfoc*^;p#0yiWaTImsDhA3+b$t<+rZh5zjOc@U$P`wQKd7ZzmTTdf9cbz zyasxV4nVD$%`}ikbclf8K$71rF26&v&ZwV@(}m6tH?d)~XbKFS)o0e5)nYQLLPZN@ zKc2Cil2RI=2Q~#uHZZ2ox_tC=$YzV1)cDNnjO`nd9J3oq$H*?0=GEfyPTQtdY9H=t z!tH2|X6gXsCXH}C^U~G*W95wm9Au#6Y3T8*_KtLpRGsW##W@1T336&CFxZoFvI*j$s`hk8{$`Tp?;<=1QlEB4Qk z-p|8vLY_FigOfjg(a-m?gy*d;T?!9!c5kc-sZo}dk`82@4x@b`4RZ{h7=`udIKZcS zrqn&fuj%TGXq5C~8R*^%htCPoDmFl7Q&^9jF8xuGsXq?r1nW-Idru9Krt}+~LJHBZ>Be7x0Mzt>Nv@u_&`oso^bvMobx69k~qB))FWd}l0h&??h2i3mT zJ-@RhZ6sX`i|N%Z;b_>Gpel}88c0iy_WwDY6}P%K6|UjjbUa|{o6Wu7QNQ&?I(YoDL^<79 zOa1KjLuU^Mt$=04uR#5~{99!d9(^YXM5`~5WF4NWQaI&>ftToAN^_il1i$y&wrxvg zreFvSHNkQ+yC|=uNQK5P{s(nNKT)q7#`OZ;s7@yWqaqNHt=j8={SQjd2m3&G#h`@$ z<^TS_6$n({|E%Kur`)MRuS;{UuoJq7{kwp>Z_w@SdvUDG@o87*4O5MIHuI?l^U^=S z=I>uvnFK4GJN%Jd%tb(#{!<0tHnyAxk6m_3-M=bIcUhAFU5e$1eMy*tE~VeU*Vxjy z`wXPVme>Qz2UppYnsT^){{Xja9WvPAXe{BM(C(IF4W$IN3W~TV@2pn%2Vl{tzs4pj zxK3o>!>(lQ`X{!=kNGC~dbZIDV5uVxSJaVJ_;P>-q54L;cbXwrn_3L|MAM8F=L1Jx zShVOfzp;^svw5Vf_@foR+}S|wJO`uW#EqDda>v$_Ws;&=wh^`g$IrjNh4A^g4YZIK zCp%lJvPL$26IZ#zh5Q4=Vnwb}D3xq4Y1qw0dIV54z{a&`pS09r+HqbgP0~Z-Rkb9_ zbV-$A{>(&uXNY0r?HKDAL!sOxzz5qr(o5YK(>Fpr9Ffc`cRKe=*I#h1dJ)3u>13Zp zMJ;2jo0vwEC^w=icG8^bSA_numG%vcnph|8J)uOm>^28PwY^?nBeLfK*6j7@C1^IE z9_I?oIv$X$&LNAdM<|<|wik1s_p&6>9{;{k*wDS|`v;(2LVFH0bpTH%B5!FcmlS`> zw?e}jNCfwH=g&wbmsNIK=UoE7pD5cTE!LRi5e#^o^qgvUHzKhE^%d=NhkDCFN8?rC z0>1uM6S}c&F=LZ`%^wNls>R{E-box8#xf%uJ#sGDu;)w`Tjl_W)H-f_!dAi;qjw-O zQEYHwt2#2Z_>n`t8Nw;Ez4)8kxx?3#28`B#8+-h*^z?5p;r_GsY6$xuS;xT(!w!mN zg*+1lyAs)$K(fZVmF@*$#TO`02AiLSDvJZTF>azwZ1v!i!ect7r>7^k{7@Djz@q?h{3@g9t1fA{gQT05(Q-TAu(U#aS{)#bJhf5X9Y_V_6i_5tW-adsYL zH;8mYx4-J{TZJid56RW2QP+m_t_qXL7QNiIrczuv!g*o00$kmXCl3RBgcx^q@Mdkk zs)`KegE%S8HB|5p&1j(X5_gRTIEjSPJ&RU`_z>!Jrs|A^QSJee$iLTVA$vcvpnWfe z1`zE&`&(URqNn4j`5hCi*yrciah^95xx#h2@PSVxCf8H&xq7L5b}zN-$0{Lob|oa@ zeL_zrb0|=`7~*M);w*ONU(=m-X@Cft$?%meJvXRu<$ve8V+;(@&$4CXsfQN>fZZg} zt&{M3eh70Hh!Z6g9;oK9DRd-Lh5^g=EVSy*b)>_LEl${4at+#|8qG}%eogr)F1Zl> zL@>m5bYcf>ASX%~l88@%Y}orv;O-wF3xg>`d#wsi3@@+kC2t1Q?3P$OTPm;g*vIM6 zVivYT<72hn)9|t~L)A^fHtg`lPcRpDevd~WOE+z@9<><7+7ON87SJg?z;WxMRC*1} zGV&8-5B}2M!QXP~l1g3kEaF0z>=&m_t0}KEEN2?w1WZ?dG{R6u1ZJvn?d2kh8S50n zPtJyq*w59)v!T&YyUtH$FBV+dw71N|b7)a`4FPo%9kb$2eDIRCdV`tKO#5#LN8Zxy z@7w@4T;_*=kBBtT!P970{d+|9oOdqS{)k9ZfGTUU?!1staeXGC#y86Or1$eP%Fk7) zRWei=T<9bw(b*;Y)dL$7#D73M5#9dj(HCOHUGALUmt)VuYFpbfW!?=|8?O=w6sGYU zYe6Un8rD-<^8lwrCn2)9w=Ynbjnv$3SpXW^^YSFTxD!QP;a9k)m!?6T%9-s~*aH@C ztRbX2KCYrxgKQ%hO6S&^8@NLw^mhu8k?4j z5PcRf!vV(BL!ZV@$JQhoBXe$6v2R7v$hm|2CzC+Fb&?#)#@UXADkpRMIYC%^rsSN2 zL;e{{OGgH`I!3CC{A|kNGcnnlMEUAo?E7=)G848KhpzQv;a<5*P{9bh9Y3ENyKkiF z?(X$pK(;ovdmN4L-N(0V=HSN;i65m6vYWZw@nY&{~h z?YyMroM8($mPx3NIk&D}GgNi*yOdC63A4lSZTBCT;vX63p%sj=M>LWpUxL`_!efs5 zkrT$Jj3)`MnPS_1bw)-G3*;uoJ+x=@n^yGwhUc!6f7pjV{g;i)Vy`8x?YwI?Ket~2T?-$8S(q6 z$q?Ahmj|M+%weXeIsk4Q^mbB}WYiVMKeVprGN4SKbA!nh#KPe9V4b-}ugH@rRkjDL zFyNn4^D|IvM*NOiodOHFVI5|a=7~`4#0ZS#J6}cKh!V z|G}wiq!4IH_EVd2g`pFZ*wkS~1Bqh&9VqDK!eMLdm8RhkgP4YIlkXCTl6n0gqCild zFMpvs_rE#?J^{u48!)1$vnKs^ocW3r``nJkM7K&O-(A8+&Xl{+YX1Q2_w@hq6ijbJ z|IPfL75H_bj*9|?8pI>+o{XL8mn-;4+JAsq=5$A?cfM@+_>DUa7;0?5R79^UmSNlZ zw{SrMW3jwfH?lq?L{vE0exUR#@Uw#Pv!S!a-vBE56gT6Le3g4wiQWKyuTr0;?O@DC z7_&pqB1Eul?Z!iSq&(+YLkro;n#s%9xXG>-4@to5;dPe@(?Z;dk@{=Ht4w4ZOvBE~ ze#S&%6!|u-?gM2gY0@vL0#a~6@x-d9e~KAXLz4w&iLE~N5F<{LWSV0}dQ-@~_8cI% z0-hKg!jv0JTQuXV&Df>&uXiJ@!~@tBlPyUFZhzptvHqOOOIbX-49t=0CApP7U0b+V z#8e%YI_f1W7w$J+wpvHgH0ud&k`%G4zWKEEP?n$RAvG7TT-WoD*Sg0Q(-Zn&8Fxaa zb#>*A9#(r;2K(z}rnNiA`f-#ny?@M*{6zT7_hC0B*wA z(nF9UBgKh9vlaBG!@@&D;qqT#kKsSeECuwckMUkVV)rPck;HNyUB-of?<#qV?u)4< z7GvMdCY&)+5%Ogu>R0@EMl4_+Z-pice8&*dpTB5mm%i*cH72fm#S?C#6jYLUlR#bK zHY)u)GBqK>GEcsTv5}*1TX)OYx^|Uj6kQ)GexcR+1m;-k<$h1F3_vu|NCU1( zNX+cMu-$&SJ=L17OGL~6klkLl{WYSChB0E5+1LK8!2%^NTqY9Xr}eN*G}fvaL1#rz z>C-7Kas4?^Xt)D(}TRpr>j#9bp%<5`MbiEzDCY{$Jc4{+^#N-D7e8nthQ*V6s&z zC8X2DAyyQMX)=$v^+r4j4htB#Ose=2(p@Zi)Lwm|K&a<_pp{?u{64Vw1xsbYV(%uL zf>|cTY1yNXW#XpN9@z)K4N+lkHOuH4Um<&q__D);V$Z6#?J&B}yU@u_&{xaKNX&TC z9JBk|?fIi$0QqcS&95$i-Oe(xn6fX8!fqdL#`$Nu6ioA@U3=+Yu{jUde`4~W?mL;T zF}Ez_;YVpoPe!vi^$8@y$NvFVN_6Qx;oF#mkRqt>iqU@e%_mqs>yg*J=$apv1e zKs*}z*>zkXG4Yqd$HayMk;Pdq`qxnN#K|+Yo@M*iV?{3{ds8m%H}G84!$qauu>Ms< z9{tD-p-#`X-XL#=*l=*eR?&IgED8&;E#O8CxTnx$$Q54#Xb3ZOF?n+Wga z##`8^&hKIKW6Ae(M4x9Y$dU2L*@_XMAG2&~q>hzq27%RfB>`U!pzDKh^QaAoGqu52 z)X>`Icok|EI&JRg2KK7q?G(ay;Hz`Er;=~udeQ$FRX5Vh!?-g8Ef{m)*OXL9`ygK$ zFPtv{s2qKQzuJYUr(sWH6r?dcPAUJ!`_{O$a?^yEl>ejMk1hIV*lt;xc7~U|HCJHT zbmgUK^-qhYVE4#@RjhgExN2qGV%kL4ru6!-)BGT>bg0TYb7tW-%BHjN?sqEVs4ZSU z^_q(tK3_Yfg%7kYB;(rW0SVkNFW&U??!Y@B$f(5R{A*M!&aWX8Fte}gv3KX;_pQKWd<1u@q7{5P_Cnz9a+HPf(wNyEXWCq1B0FF%zBb z6dUmS+(XXnxx}{Ws*EZ69$QOYnzK1PKO7XzgWAHT)#sJLrkyPoQCgA?E(q%DKuX#m znDhfH6DwC{x43p4*zpTvcnn04v0TXVjq?__Zo-=L!&< zStSjCk__1OwV3>q8{BWp1wx1^0&$j&4dt8rx*i0FS8*Ck!7lPR8b)eW&VQjeDkq=x zEXIH8549ROYNFRzAs}XaRZgZ%^aei(ZD#V3N3;I4Mo^?CK^I$*MDDj@Aw#Rg@%h+Y z>Q~n5+Q6w6&&M|&(p*Hthj*({^;1^B7z+s1+wc{!?;8l0cQ0@W0Cz~GU@h24Q?Itm z7~)tgT#f2P*$_L1-Su*hQc034EepZFW6rJXw)QInQ1*ZE_SQjhb>FsV;{*v32u?$A zw**Ka5FmI61b266BzS0OB)A0#5(p4NaCdii4bqKkfHZ-|t#kKxs$RW1zwgzpx~Fcv zKbk5QviFj`_L_6dF@_t6r}oO*mK;xwpP9mzb9zW~^_2w~@z;$lWAo6jR!5|=$T9kv z6=T(+&q?;QWGNCDk+K>LtwB-GB`{c1y1?C4)Xmc5_BZ1zcWMr$tep5{iIHuMwv*Vs zb)=85B;3Qa8XW}p=#k2|Qn16DSvkN2MQxSGOy?)ew6GRn`xxsq88r%z9HKgY2JyRT z6Uj49<%-7Q49qC36b|*KZf?J2l>hv)iQnh6UinC+_}y1Vg7?kW0KgY%UtcOfVpygZ z#kcKRquC#`DH+akNp|;*lc$TdQo@^r;{{J88GIb_Y%oRa3(cvO{_?X{miJ;GU&#=- zhu|+wLCm=KcgOkP!VU&>inMi;RMp?!Kg{eyQy=HVel>A|t2H8qV(Sl?<9A~H-de{h zcn3YlCTX4^2;BP|v+>!GzESh)k#VLH39ZP3P~(2OQhx8$*Pcw3yi2$36bZ{`!j6|G z2g1lu$0wi4Nd4@FSwrxW2$HL?E`7Ct_lfotK+~$rcE%jfdsQ+RBF?mRX(40A`vE#a zGD7iG(xY6hk;}-*UVO8f6xulbtfM_4y-i}n6@16GQ0WyX_qyR{-ME6S*o&|_2&+5v z2URL%9PLw9TTM_m4Wj|x$R#*92iNN_CnDBJg|x~VOy`oe6ZB%#uS&q z8X@$Wgnwj2K@h0SK#Y>-4a~eC^&!G&mcf!x;>>e+aA%~TAf=h}YgKx)lj=_AiY{-w z0?IV6;p^>G{I>FkI!TtRYZDa6WbG7y2*lnKeAImvY^=Ct)%>IUt={a>S?Bq7K%mT5 zk2$x#frXCJaWAv^hBGr`<9!&u)T8~DGL2uAep{+aw(&fDQEyJ8wkO8pXa}Nb6-xTO zap;MIJxB&jrGK`WY?{%o`1&hPA)mI}UT_`(_>Xm?5@{aqB5GkYmESvs^jgbBjK!9fcLCvi<+hp&+uOOk`1PTwe4tx{@glouw%g+mLt1CwR-&f_|*E;bmluxMkE zfxLg=A{h&gQp^vPt`|wuN5kC0g1O$6H|=>N&RD>*mk$pk7Ey)-dJ_{Qmm6 zcfwyxrMYn=LcTYxG@2{W^du8+a?QSL6GiU84riMYiCUH1d?UI^5I_~ewewgahZ1VH zaP|jZH1WIr6kl*%__RgLcoLy^k{08yd2uUS*%Cp0^2fY)P4^3RtlW$!j`A#gAtv{fltGkY0VGm`#A^>SFW;^rWG)TO;8k6?Tv#ihW1zIJv!cEaMC zmQHWk2Vxs3xFJJrj-l~z{9A8*;lY#{_ws&?YnXcu=N8?=l?qzUo==ZHi6#bTMSp2L zH_^JVz6vWw>~ASG)HcrTGzprSId=Z?{??NZ*Wb`jiFGCyPG{D07}gM?%7cpBr`}0# zly=)}O};oXsR8a^E}^c8o+5=zry-Uok+EL~%+(z;KU8}&$5f=irC8IE1M{goFPz+K z6W}#*cuVe*--6EYzMK49m}=zZ83nD=7_>`u!#5CKwAZ6qLbzZiqHyj9lYA>?dIA4m ze`eMODq;b68Jw5Zp3eUo+$vk>=?7?cfm$MmTsbOETw~g#HxP%5=|)4k21FXc)hR5W z2Y$IzL)LmkV#($x#-ya(H!B+*xo>QPDw45fgj>J87qgZ3)}S~_aD#GTie$Cwjo#wL z=xD~?g7JcT^uiQ20(AnY%nnbud<#}5`#vztf8lFxYSi{6tS_xh<(q58xyDN!dGxY+ zz)g_vsxmyAQq}dLk?Dc117BOxeH$7{_uj=kdMWCajz(GG&K?sIU#;`o3ViWLf|V&n!aqI-e$A8ptPB2f|M*QGu^_SRe-! zUM#_%NSRQ+Zi`V1eeYEa71gL#T(cUaDk*<+ndfP8t@?A^+?2yejOY-^H@}GD2R(32 z#RA%bfyP;RbFMrW{>{gq3hCBd{@*Pkm$j=DyW*pF&)NS5Ky=*Vis zbtP9OX~n^PdNyrR0DVjnHy;K5)pNL> zvw_CAJ*R1O?b^)&M2pbWMQWiiwOxG)yx8NNxncW*UO2tpFR#~|$JGTN%hDX{6BSrs zrDx0X&T6ajnh#6?`whtZA_!G(T+t6sik2N=xb@9P7AS(NkZn%XU5z#zUM1mOdD(PE zjpu+vwX4nm8@9j70}O`n(2IsT)?R)m(EC{_to|nP?Y9EgdDrQ4@8koP?$ZB}3i#iB z0&je+&?=0{e?g|7VEY6M(#0>jCp{F&@$gBMTp(t~UEDHVSsV|M3^}E7%EkC2O1ckuKa;B z^RqqRFPZ{*VLcN61!ZuVxZd*I+M&t*NZjfHQ0=F}i^>a*#9Ab9;jO=*O9{Z~{n8Ki zGO&K33k=G=67%0Ir(IJ8kN{~4zyQ9^C_N31>|(09Aj2eN2B|0q>!wya&~T}LXAkC~_z~-?mgv3DlsURiqYYG&K?az*3v$2TcD zn>yO;cV6(P0+mw>Fvl!sxWj9bM`Ni67g4NW*c9Gw;lD=pU*oy3Z$g1_UHq?6P595d zxzUpc1v&?XJ2~8bFJBPpr^nYyXfnRSp5<2_b!);I{^E;kXNv zu7_1i#^tyG*)A|pBeDiabGMFOAD&lqn4<@-!~j7Al3kb!Kpg2&zF0%5|89@F2mb#9 zk_*K}D4_j#p96-&7TaKU_myC4K+NZs5jJCwwI}_bH}^lB?10PvL)K^;Ze#A1>f8J8 z<%QEvVWhsv`i~5*Vl->2)7~bi%(!|H8r0E2T=py38d?&!s~Vc>QGC|fZ1Im1%W-<; zd4m}7{x!~R0CS9rq(9+G5w^h#3?&aRvNkYhU_f5(!5n|(peWEk(S0b{XUNyO)}ny_lMXI(@scyfm6GyQ6s+Q)29JDua$IJfyA8nDL+MXs&-9j#t&f zb-~uslm`8-ze#39m__U=cbuAaD{rL!-5$+!!d}H*d-6En#)?0SG3CeV!Q)zcQTWQN zsVc;aW!M7Z?zC+}MHx8PC`@RbzY-bzGQ)?d?~^uaKL>iY7Cj3Bey$`q#o;wbbVx-CD`0 zKRHk}^8cB@7l^gHdO)=tmbQz?8tL-iy5f-oO7Plv);ozuH`g9rAzsf7Mm?J(GZc+t zI5coNRd=?U-)S+DZ<;-NJk`hd+uYA0=551b_0z{6Q?qI2&|s*ZI;JmPfA;fvzP-7% zK6pj46*#Q3rmoeM?4Z#{zM^1`kEz4oC?>4!8p58vE52oc68hMLHx|ft)qau&h$z3{ zh(u#veVm8{hnqgEe*tX_Fml%ZOjXU00Z%iWkU@&sq_+rOU-==_=V z1BW$QzBa!98fn%iPSRwKhLo`_o`K+h7E5y~!l)%0W#q8!2b99)4AuK>8bunOm*bqu zyK__?!XD+#wgo_r_g)|G7H+C3$=Uf7D_c6}g(}y~v1brEWfruxG&qneG&D&-bp5nt z5qUV@$w5%%f32~9J_E>bGhu}|9T9N;V|NAmXAAl0GYC7b19nc}8TiD^JX`+A!2Yh$Un>v78fXZ#nSbn%Ecniq zB-CuPqM+e&O8rMe>C1_HNP&A1{M@n5o)4>fb$aF@N`f`yFYC z)jkkU!gFHla&U*e*89E~kCU6N7`zhjqGNcTaHIA!ESaTzWlnYEwH&F)6B)lJY$?M4 z%`yZi5WM5@*zo`J@G6i&>b4thP0Rnq=aCZs)=c?#d&}yKEuTzx$K1w9J3p3F*)hF| z*IvIRwE%n6ZbQn2s5^D93kL2%i{@s|KMZXy2jLFU|A6tW&{-*#aKV|8VOohITv+dl zNOy}s5cFBz-E&{-8FgA_oZm6;9zrzoRur9cU8&8Yj;jS zP)-1&*q5p+hw#p7<4+XK1>HYWCf(qfP~)d%e4nR%vfEm)?AKwt=eZV`>5b&<2=tMs z_x<(|)@R7D*X3JR$zb2XJP(z*FD?7kBGm{fcNAGu4219IyB3shKVYHu+%Mm4IlXJ; zw5URGYv{51o={tN0i3!_bl?T~vonoc>re@dI1Tu=+xy zcI%XK7=QBlNer13p_JYnBy&X zuABFcUV`uyR@=Q=pwh&3xLXtTXiSS>ZE) zH;tb6l%trB`~D5fWaU~n@3iqsO2)2OLxO@@sgs?rNk!fxLj9g$_K1&nuIuVyX1Hgr zQAum7R}F|w9Arm1f4NPe+MXj7?JaNh8>WC+MIyI4?+aa2TN>jVT{skM-y(WE`sZdo zA6?sBybdTNYKm_PA{yQ~CP7L9d*pwx%vBc01Ap zrjx=TG}R$s@g?bTLbvsswDF zr}sk~;YR*Z-!fhf4LqmrXBENUjm6p{dFUIuQ8-u$CW(L%O1>)q>Ak_YIgg{A}AeD#u#&gKo3et-^+W_PEJYN z9Rkqm4AczJ94_$98FcF{G}wp7rxlFm5xywgdxQZ$ne7Z0tXGhU6pmo7hIJ29v1^nToPk*fV#`{vYn6YafWSQFY zSqEX|T=j3==7bwo2DQnFmJ@d*midOv_NHZc4lwhb9>(&OGmZ%w&>pNFjwH^hkQxM3 zk7gdjhkPV`*~~R{Gfb^>mT|u=Ix=Kju{#Xw+iKMOnQI!e z3FUMZ56oXLhMD&$l{UZv&C*6@rK zg5VkwikBkx$9k-g%rDUH)*q+{WxA>b1RIq*&$673IwLx8fOj1Cq;|`kKxaKvX47a5 zsb+g6f8l%N8cPZfC2q1Km7{EL6O?1zv!HjhNpgryRz5C7{sC~~(9OyFV0HjG_WDLb zbRXNf3n)J{!O+Wk%R0w@e%t&7iA3D@{smoZc5GI}v;GAI6r=7Ek2?T&j$!HWzo5py zptEN1-?{(0n6s(gt*>G$n$#h*4MH}zNcktM(fRQpHKH|K3$+(Slz3D4+vqQd5lq&3 zIQtg3_heJWTj-$kv@c-pLMy;=`|js7mLN0a#^$ZiWs}7a14vl$_|6!qTM5ABXLw=7 zQsCY~Alkg=SL}9&J7hqujoK!BYFnZRoSktc{Wz&`MedjXq4lLdEni(M4tMSg4u7a3 zY4n!*2=xil<0eSpj3)kwIBtBuXtcx9>TlJ&cCS05Y&(QC@-9dlqvvbbZ95Y*4K4|( zae(=|ycI5Q5mQ3WUktC5)QWj?%^USJMB^El+fXuZYx89``FhLK56(12Q zJxNLY5=1~~#p^M~grgDZ3vlpVDCCkPl|Q5j>^i)s^EMOZ&|wyh>%~dIW2#W56E{nv zqv-v3TydlcTR7{)vh8Cgpc zt>?H$%beVykG|GRIm`GdVAz6H-*TBoH@uYAg|O zA*Z9W!@YZZPeeV@eT}lpAZf3-Ktn+u{4q7mQ`neqV%B26Q%bp$nNM&+Qadh3Wx)-?CInYrD*o$q)bsHgP@hEoGiv|I$V9Y@t#J7k}(ZnWsNzJ&^ayu zX#}DVnk=rn(r4~>775e?9=Fx8?MyhgeD%Qm)$ZfiJmk%kg9j2o&S2SQGbSR$quP~K>hTz_whu}%ZS^-qXAI2u}7>GJ;rU5Wrr)5 zsH94(f|x88M*MXwsbU8{0%4E3YATT96W!*3%t#K)EiSdo5Y?z0Tl!Bd>5tB-Sh-x0gw+j%1l8kVnx zwv#Lvupx8&E9IBoVD`(4@iv#4aeBZZDSpePJFYYtUF@A$w-ww&k6c{U%t$Snyg_%C z#_Q{ryAEgibTHYsO^PG+2llK$@Rz4MMbxZ&iLtPUJyvBMEV}X@rxgYuBV!1B8CY=4 zjo3MFDA5dn;SPi5fZ}OIUR>K}98|=mjR}cw7l?8@tBKPiB=(7P-S^sh1Lit19C{6%=3`68yvn2%t6%Pg<07RYM^y&k`|4 zg)ruFC8;BpnfAot+IBAUs5-uLoWMx>f9+7L`J=<_z2I2S{hw|`ZyVa$?SDAb?IedGc9@N;GA z7aCY5;p5dV_u&B$R5KPXIfbNFI}3)L7VjL+;rR9tXfm_(CPLL zE#|8q)eP5tQYR~-fp?u@IWX~0vDCYIxIW@B>84lNA_~FNENlI|wQVXx&BF9B)OKvJ zcf~~Bk=(LGQ}Qv8e8y2wLY)L*Y_AiyAwlVfONa9osVhI{F9-s3(9Nm)QQ=M+kC9W&aYO^+lEhVCaKDnQogID-5m>5OZvk8!lZ>o*=?UR~= zZDNxYk48$64||V#I(xpIQ-ii#rYzU7at#PTnP4TGDFahChO61VC}c;|2%AAHkh^JlBfnmC_X!S1(6G{{=a z;ft`N?hZ01&T82Dy5)NG_S=C3pqMmSV#mt}UOEAGpg$(Ne&D z``o{EzkJc(g(sCx_|x0=*^BfTM|DS?NLDg>dvSV{WfxOoaLR^)P@_=*}m6z*fz~E+I&*9pN+rOdDtUH>Kmq@0O+$cuE2@ZJDX~Rs0B6> z)uw!-$6fHbud$(tSjj^#K`a~?uM#pcZVtFq@Mi_WF>>Q%i@L<0JR5wE(Y+Ot3-jVY z7%a-36!Q%&k#le_4agGtKYZa$7$9^~b4l?H<-G1)US%3uJISS^o9- zbY;Ks?a4?p-Lc-7uQIYRTW^fLA|j>ENppLp z5`v%L@s3uf%w2r;yIx(QRV)t1CtSGF{S;G45j~Q{en^8PW$#14eOPv~%f-90d11bW zIgL$Kt;g16D(taLa4d`P=^&|ft?k`I+BzZo%Ou4I4di9fxh(iG+@EByhN)Q`bg-}? z^vt>_;Z$}NU6)a{zaZ&De^1HSUP8k-eJwR0yZTbhhnSlA8 zn5Bw@PiSybFXu{oZJ1)$*jskY)nmW9JV=r#T?Wtb8>zY+>zM1bHx_Q~ct%7;rl6 z*a=ucqIIQ(E6@y1vZ{Zsl=I^!4xSf?ln#(>avo6+4X|C;jP*g=IJH92rDNx~wIT0a z#N;3%7CojoCW~2^f-cA0 zt;||Ve|br>^?knzvhg>`?~~0*Qh2XarQ_3dD$RKKI7dU`V+UH^Zx5@(wAFcS?)s_m zj*ys)C0Fq3cVF{8Gdl0Y&KtiRUwzP#PHZw=kksqVW~fpXb;>k|oi!uW{uEpE(S_G9 z;@+I4lsgy@onhxg>h-uUuY^_mjy?Vj1orNURhVlB3j}`R#*~QIiYcZ;G&fYD>CgLRqAR zw|~ovdkl!i4S)Tn0de;N6Bw^7t3jT9BOkyW%0pDg8(BCjqmSPZ7R9J1RHO8=QiO7xlCIjTAH0@++o}*1o3s$SI{%TU%xysKw~VjXR63 zbPC9puHWMre`f+L-Q&01;v=6DxS!wt!CoE|R<^SKgy<&}NZt_`>tl%bk;@uIt$!t3 zxC}JV=RD}3tB*z?xxU?h$>o>!cs$059quekMOgh{!@aJk3&Z?(f#BF7of5M?rAo(u zY#E67(kkJ|FQ8}3f=08s@jYDOn@|ht>!WOa?u0aYXSICM(@XcAug*)E@1NIaBOiD0i0ME(3JZ4dn)cGavEz9>!aNqS<3!$CDfxs6)5@q^C5j{Y1UsYGx zv|(7`l_&O7x-!{eM1JnBX(lp!pB|okx{t099&1+P29o)n01p zgx!fQhi`B!+be(U0tI1#3J=rSFnk8WX)_QMGh%(^PjsDAfWSZSqSk#**&#eW8L}Do zpiY%+ldf1Gyk!1Tda=bU=R=PD9OdsZ6#l}bg^Sb#E$RQ@dia48En+<{{rg1ode_J# zjW+j=j|wZCQfYmn&OT3*zcf5JI6~;PH{dDG>^1vxbTl_M#VYfPPP&mRxcbe16m1k(|BgPj{5upv3LDM0fLME3ywLf4{Yq)!BH*G~4(ap=PB%Fe@WVlbN0 zw((Ze@q=37#fWdHN_)r8ojO=8F++WpwET2g{#?p{%h;gmJhJ@plg-7CDPx#6%G;pH zZp1$PhF%&?WmFPG2OOu*i{n0bxNzkqoU9Xq+X{dCM)Vhi3ncDza~e1jy!;aw4#gT0uk3n#)C$KR ze&(|dKf3MXAfY_t~4 z?nbCQu95Qz*rW`f&fvjrLO}@9g35YqZKa^K{69^lH`d|;sSeg?`8&8AU}Se55?Apy zQ~3?^k^<~$8+VHfOPWuOrl z?7ItO-qQpJor>%iI%q|2o;b|c9H^Uz-`)~{8mdRx_Lf|vRx(r73Y=nbm}nV^0k%iE zw6i+n!6l=_yeov|cryGbQ$2%$({Px05LCjnjEZYeaMh;;u2J%Sp+ip_f2@&{tdeog(l&;pcbeG&sQR$QMtNi-*`wzj7} zH>3+sNrOaY3(^ue{f!_)9ozhK?+cTz4nA)FS}sTg%zpsq8b0 zq=FqMn<9K&R88c1s6;cUzC6zLva=~v_FiQS-niwvKdUNzxjDSMDG>#BFa(|b&pO%( zoM0Kr)UgYZ45e4mqni;?^$bpWEBVS6UIk128;A8X**ErQt!m1ik(!&3mq#v(y*Rfk zSVZ5~n;KKJX3wSJV(S-in-s_M#pP-c$(ygVeC?zA3u{XYhUNV;OXYDDx!VEpoBMW_ zNxejqtnAOnN@84}$6_sWes6;*UM*~xxNZ&<9>1TNKYv!vgIslwyACs%WkRE zwPo+(L*6D7>YLRL7}<=PD7!n)3SsZZRuA+O_Fe=)yHCg$)_p?H!3@UesX)=`xIH`j`;hKrnUH?uO7GiD8?*W{n}&We5CbgyPT(Z3*Hn1cv(!Yd z=N(j_I((PYbCj6isP|oM2vg$z{3n%XG!PY5>+2dq-!3w4MG*N>=(nrPQr`?$qQehV zy@W$%1CQO7jN8lJ8)aUV@w*VH^0oPJ3>g(Oh3`1i{vyY|P0+)}4m1@(v6;YB#iv|L^P+{p4)l&7Y*Z%+VZ(uaCHjs>gjgd=+5pW z(#Lr0B3d0Z=vcNIWBAQBBYG>b9kRi5cZN@!DjI|o_HTfx2$21uW?SmiCTlSJm8*t}8U2|4DBd#X-`^Ud z`>lEVbB)59TXg6sty?~ST%I_>$X%DF-8UnJir_`nMHVzDWE{=-`={t+&tIxHB>|@Q zW_;PAzWf$R?Dkokmic*!TinP^My_MUkUI#V|I#z7ylLA?E9`hvcLR&{x@VssocIEH zI+Ryc+a9ufUu9%k`;^HK;{2wxWrL=Lgc!yhWrzQ07}PUzYAbiYtR-4wDo5Z1%dU`8JV_ zD9AJBErx))x_O(1u%v-MZ*T4E8pAhY9qjXI;dXrX!;k9A^vui-O&>3~prx+F1{y9} z&rEoFrPyYV>{dfZ0rbaHxjb*t$Zs_@Icp?e&z3r5gid=sgC?Py06B`tUm~KC?eJs4E@v>gBDLK?hktwnXL@w&=HB7n(lOepgo_(!u6MMcOac8CI+_ei2B@Ei*8b``D%R z#7zApA>!`&hBT2wf{!0=ajsgi$)u!Bq^e(Myv+_uj25euuU<-TB=qq} zM>CQp^fwrq9L1nBiycl492phiXfvHG8y?!cc3f@3{n0N~ypAE3Ue1I{mJZ{Ettx0O@@SV6$h4 zFt`($MvGq2ZH9Hk6o}L@f*bVDzwDh_i5&RMvR4PP`Rycbw7W=Evb`OP=y zqUAml%CNHqSMD$Cs%Kq&zA1_qsg;UaU9ZNFdvZ0aw(~l+nY`@>A3Mu`VJRU@P z-HKif4(J8qA7A#llB}%BJj=>&t*Er9L0=r(K+2MljF8?U`_QNE=`ll3lo{>!;#th@ zGoMycU)@N9eG!AEd_S`X7!(k1YZ~Sj1m+BqOPvxGSno^fu z;_52#=QK2j17ZTrf&HB)8z*$=_NRaDxt?vA9cw(0OgX0L#(HX}YpygwFo;3_(egRX zMq0spK}PAYEgIBZ$-*T}?gp=C@|xrL1_6LhGuwgoruwUDyLm>`dBK^<4{#c2=$`8* zQ^R||2CR0w)3dxvbZ%?bj>&YJK)q(8$HscvQpXSL zGY28~){h{oOMLe@05`$Ga+%%<^hcI> z8UjJreBm$hg1Upw$}3jFydDlIYcWO*a_AL@V^MPDk#-Wa4bb$zHj;qtq_+3hye2Mt zT=B^$uOyVFi`kYa&|c(gp;jmgI502E&b8FX8XFOMIeiu`t4<%uD&2iPq^}pY#j=AK zWGcBPG4Y1K-y9I)@3*DKQCch;3?}U|DIG$@k~G(2Q;xr!VaZ~z^Fg;OtRRM_EawGk zjUS}{5psrOsRg$V0m-;i6mkF-LAp5W`3qTaY8TlS{o7i?P_Xq)p3qU4cTRGF!t&#h z6!wR7+`&&S4jvsx84~lqH+?$4FV{dbjOYbRxgAbI2{r60M;H6na#x z2lWoWLv61EQvjlP!rN4yZKCQiF&z;rG&F?!@*|O-FI|q(r zLAf5WeT57p7_YECwYoDV^$xtNzeIn@sjcZezkzkX%!MjDo`fYm>n+}V$~g(Bzwf)D)8sv%VL`_+>8nYmX@u z8wQFOh2X9(U(Qb%t?-p6V=_;m@XgY8x5zLBr^VEM;D9~MZ>7H){P1}^U-P{)-P}?; zmxj)ots!0J+D+Ks93^zyQRI*j74O-a<}Cauj6gV7F0N3h0$7ecxXTP3M$~SV5j%mW ziw@p~0V}Z5^LrnpSE&&~VlaMfG(^H}y6TOHIFqOl!9@hXfEozY_!2T}(k+PT@2$VS z&S}Pbl(6lbOm1$;5{rXql;)p2b4<$+M;(#x%2AVHmgH(%Z?A`ksS{2}$pFr?`10+; z9itaUksFOuF1kgn8HsqL8!%ZlU(0LD_|&hEVL2};04@J6g3V!LG5cAsC zLbEtZbSmgQT75pg3R8vq?S`e4YOuIY^7dbl_D5$>EPs#axmt5$U@?VE?4@Y1osh-5 z?<|<&i$uW2L6GIv)IBf;%lj$*11Or6K0Id^($j@`XLVL&W~y!$uZL`^B9y+@DQgVw z6wBQ%B6EGzE-0$N3=&MfGiL?2ct;1i_&s+um+-gZZ(ot_1`9_2jzy}!0h%G z;+jalF!YXWfXL@_JTxV_{|^bgKg1_ml$MJ?s(gdreG zZapxQ+=Xva>#h+J*j*!+1~1uO8(j<#IsFcY!e zuYEAcJf|^YLq|v>cHdYDhTtP6SGxX@p_hHL5Vh06YHb;NPz~Kl(b!IndiDHWJQcRp z&H!Xp_k@vVhamM6pjf5YXf8wJ3}(Yz4^m$lm*nRNLSD(_4ZWIpaN)mp0Vhk#hk@N&P z6Rav!Bs^If`y`Ivgp*cI7 z$oyJNJ)vEUqCYTO@rRk_EG(O3PXGcOmlVi~yQ_(KpqN$((vgs9;*`t@9A zPG`F864rO_q`rlwFvT@bj>wp8ECJ^2lI^i zhFGL1!Ee?j3CUn#KLhZA9*#GCLK+>(^3rX%;s>T^aqHLm3|qZ8i0Vykfu{6Npj@FT zO76hj*^3WrE8tr18ekHxa9R;~pV|7})ySgCg6u}ws$!C`WrC?+D)9up&zFgaIFSzB zJ7N2A0oM*0K`D{3;^#}v1ivC1!*-8#!%VCWAG0=({9tew>>bo~aKu88co*!e6(q_` zjj!-_8G^^NlMI<0Eg(O3PAS{gbK8!~Wa0J}$7S15**34hwA&`zTyrGLdd{H^lUBca z|EmzU+4NrOXh7R=BI{XJM~itX*Ytww+;0;lG7}lv!AH$Pm>Oj&BMKzBCO>-qP|)oj zSL6}duy}bjCQ?59^+}bQNGV=e4EtR$kT}I5L?`Ta2u?iM0dQ ze8J@5NCXpL^a@hL6|@zw>C!%|WEVWGk7tYLQ(3;xeWxSD*ZLTA6y-a~n}CSbkLg#n1|j1VN3+)1pNR=UJMew?qIYVxp58<%kxd>3nXg0Rgb91pV`s5j?_-(e%Df#h|`5g{PY9T z%}IKn`Lj+M?y>doOJP95yNr=bg}Sd}4VrN0WYQyII%JfvaPX%hUCr{4Txs{?{Eqhb zL@EcCOLc#=nLo!BK1Y2%R<%wNig&O7Xd-sUmJu8++K~9&kE$plETESjf38TgH$=uH z=&nN_wOpm%4jeOCDzW0f^5M5jR}Nj=`|Hi!spmUnpbKD|kfN7A$NRc=wk*f;cCDFp zyg@%w1^{2o7RI*+ggG_J7S6@HIK9^;x`LgeZr+@eN5?V)gsFp7qoWc{yt#8~1v9(Bl_ijf=3E^}%o|I{&e&q5}sLH%z z3WECT{0Ab{MqiSx4DUY6^fP_u$^40(0I!?oBUwmZ zk%lOyD0UwOKk>F$0)*&?YB;=A){~?ucn6d#T4~bi9s8T-wk+8{o1)%F_2xFtFRU>6 z~Ejo32tHRNGXsW4P;WADJPLj9{f_*(*oYCD9 z6pSm}_FkO&+6`KgY}CYL=Sb z{GnhvYIYm^-$j4u=+PQ!Gb$Vr`+UDfD(U=0gCMudBnwB6c5dZ}bxF;#!D`KT>x~CUe2)4D&sNIg| z=eKgK0lvJTV;!Q^XFG;@2^{>x5~m(MXOe%=l%0L*H zfLEeHlfVxE;nV-#pf}kFKGu+iPXKwZoAS;9iRSv4n9(5@&p*Er^0&|Ggb?-ZgW2YQ zo3ue+@AzL;3>m2VC*>n})N6es}4;Duc?ewU)R<18pTMTdf#R2S0580g|5tHBR^S9jE?F+8a0m*1}p-wzO9<(LLCCdTHmF`~i(lCjR<&(;@7?^^_3JbcBTt`M-Dp;F^(6S+HjUcLcDzAlU!O zS{ViI`$QTcfsTf(p)mn6G3q7wUkxY39+kWKe?h_O0H2xUDzu5@20v#xp-6he=uRI}tW-e%?JD};E!QwKBgd^BY+9`q_$5^^S~2h64a^l@cXOS`T)^cq0B(v8@I~g) zZQ?zTuQyQVz~GRUY^+F62Jb0n5yvm%4I$P4ib6lwxxsO~aF0_i{pSw0Wi|}E zlT^Q$0C>ZhK7T<$snT}|ivMac;{&cB2E4~}>d@CP6y8xM-1AoCW(wd+W~K+oGX&DbjmK=}1*dkdBC8p?9efLX{>+0O?h_f`W9ECcP7+N)zc2 zdKaXI7D(~D-@fDCvA^%P$35rlvCsKyk3sl@ku37A@~mgAIiEQbxsKCNuDI}-yh|MT zqVIoT2G(t`R((xj4qE|4$@<}` zz(D+SDJTC2e+g@8!eC1;ff?|Y`rzK{_gI&|H`K`;bsO4AX@>pCDi&mbs`L450VQ%@ zt!Y0wTY`0`4-2l_`Hijm|4V28YxiqoR2LU;A(QAW;Au%NKB|mh z$5GxmiTV?XXbB~cVuV?MNRJJTlE-IL14ncRiM8Ep(d4uD5KHT+c(l8kY^lK9tk{U0p#zg8k! z4r~ko3x;2TaFeC;c{9;}Z_4GL6AdQtzqAGkd_1nu21mf0;pX~3H)BKQuyyML7;f-! z{9k3Ug@645Nj52Md z#>g>YglueQ0Mj_|8c;(N0Y*PXlNh0?F+4VN*8Uk6$+g(z!M}Q82W@>M?=iZKjnBqB z`p@=n^F6uuCsa!EP}g-13;n#V)ZnL6vSepLR^kEenv`6}?-y4fm$81A)r5^D$L5QR zH=UVTUG@3BnKYcQVX9LvQ80)Ehijc>Z#Hx%qFo3|G7C2J^iPK>QZ}c7}Yu1+sWR3(wPNuT&<=GRz2w~wo}enY+~)rLj0&KH#c2e zo>Q)W&LO$5cXL}upxNn;`I1!BxVYIXD$d)_u?Zn$D02;mnfhv!(TZCQcYL|WKGsA# z_2@_R(ZI#aIISE{PV+*>uBXXiV5gNBScCI`K?G}Q-_cFngh?(%%|wIZ0+~@g)xAUh zxc(W$o?fhTs;d#;`{zymHlKoVhhWk9E9%s>^w)LA*g>+AoC;6oGL_sKM!HDUWMZl6 zcfi4im4o*s*7nc%o40&yXx|+dNoMRs_1fS5+&5ot1j`UidS~Ko@)#C}Q^s4usR@SN&-?vTx+ZM72kjXLr*+AvJtD#v#=+yN(_i+=a_F>-E6_pnkkprsb z3xx+Y7ZD2f4D}M&dE23~7lkUHF7GAWhE%)CXHF*Gv(U+pU7uQSqWzv_a-+~KT!6ow z>urbtHa|oTHFR_lgSx$86N89O1YkcKN>^Hu<=u;HSN%XoFIS51c8w6vFGsweq~*2{ z`(FlL;Fcla+M3A1DxLmPm84(*A?RALE!n-qu@SVr{maYjCgTyHeUD}Y~f&%7$JXT^bdf@$}_0itNEJhdHHSzJ0qtEb}!IhLjXx^m`Q2TaLU}Cq1w(uYf zRyr2y0VKNTc5{VL%B7=g@mx0ovh=3~G7n9{4*^tOcI$&-kt5ZRdG{>itPlT0`uocK zhD^ssB|hil37f<^3|k$5IbVB3l(e=^V&uI=VQXxYhc9DfT(^Qe#HC*Cl3XmcnJtWo zX3k9TG4n*2&(oh#N5kt3qC2@D)~v^6CpIxk+G}8v9*1n>=n6~o#rgX_wq@L{5ITh7 z=jFTfqx4V51nTM1T?2U0%4Kf`MXy!KzZlk#!90yQ7pYCCi<%y&a%n`#@o?*~Xxg$s zAI86|nil^S-Ouhm7K--mt)44a53X#yLxv69?eP$mrQb~^oa852Q7@5(NTbU zLD_K}*GNmWMZNYS`n?xE^a=eTcU=&X7fyDf-LVq#7=k08T|1sajuh-6^=Mz;L)@wT zE(S43Mbuy?^o=a7-uds!*zGw zs81ihoM#n@o^>$IU4zDdc5$F(0>$EEmRB~a3hPToeW=5lc6lsj^!g?dJqMe&+eN`MDJIgp_%2|bM-5W zTq&iFQUG1*TWs&+*&R~7T|a%ImOvS7SedMYqf1XVG$}(^W=oQedc@-feY^_vT=Al| zcPS)InzMdn3$U3%bMa)n7Rl_bs5yd#P-Z9UfMIgW)h$bA955 zbNH_Nx}P}+Nj;z34WnS|vsOmc9BXTh*Msp4ACn>-Y9H zxrazssdUAeQDogPOsXOYHMEnvUfk>RvL20s}5v!c*w&avl_VDPBHS+ z4EV8p0}4T?x_h7(KK-4*{7PsrttdE2Smr!_AE`NAlHtxh?Y_0xt+VhnkYCb#@FtXZ zhSYsRl|Sx63ChjMa~!k=?jEL2QV~SGIj;NGDj)IEhJ0RsO-FG2 zOTMv-T+*ugy0m1q=So?l=hvwpi=s@ za8e$_lsYe_u^r zTmsrKYCZX|Ik5iw19R+W`(`?Ae|CsZE3gNxCLKHCS;GhU%>r?Rtmz^P2j05$Eudyg*>whhM> z>iZ^{b%B?hZdJeEp4L2h&ejQN68r(N%Kibdp@e$jwCx^iSZ)1d>r$^T1CZhX_oGL- zf!mW3FQ<*0^GrL8G%aSl3Heh$IZ%$T+k{?MHTbL(PhzyGKEh)$K5Hw?*8GiBiWQt( z@elBam@M9Pw@>U!wKO|=e&!QO9U%-Q7(4UeLJixrpp1Zv%1NdUROtqkbyY)yOyy&- z=K4FggKeE~(OA0qg_L$WYk`zH?j;-N+34Q@)w#jSV4W-M9Lx1&QpSS}rTDaCmQDA~ z13Q2JFMEvHi4~`8y{$Sa{P*HVd9f))f$EBSryu;d7yvaJlhu`;WLnIVlM0|TYdl!m zQEU_CGNT(@gS=1u;iOPsIwOu=ylvA_)mszf$yHl@ZLq&_{M#mH8-Aja2xMq>hRx;7CH}ffX{pmR=o53SqPfSTH}% z`?eAT$p6El Y!kCp6RcQhOpm#kP@lT~xdHbE#GO-z_1q*)#`)bBrLHFb&;0e|=d z@_=3Ob1}m9$>ecqm7oCUzgM+aN5lTc>v-uUgg!9H+Dwi-&cf+p^S>=%i^^N!L_26HVVflj>q@*&}0qV&EQn5~|(tcNWJfHHLoqaJ_%H%OrF7z1aGU z0|}+pvw2U?#BYQH;nB~Uu5 zeT_;=_OE;~djetQ4|$xZ3LW1!A~iFctJTUk8NQ2dWlLBI&NnJ;WLL%(7iU0Oz*+3I>|NTVPVvqrb1q9I;)PVZ^+gbFZO@F z8@bII_O*Ix&Ku_4xx;mf%?Ftw$WcwJ%A`JC)mN6tQ$rL^z_l36NHVCN`ZVn=eex;^~DDQ40!UW7?X#pu-{z#HeF6t;ptf>7=D)o^ap4Zk_9E}|8M$hJH zirH0~Ms??{&6Ky1sx1f$J{9wnCYE2#!YYS77Xh0SheB;l4UHaRg3u_{cZfcVFm(P9 z%^k^R06LQ*aVYpW(sCqVU+lVTDAW18dm{A?O(YTi`N)e9!w4w>gCXyy5TwX}k6*YV zWIE$1B$3e0pMg7)upiX*FuA3P%>rS&8Dz||%OR#@o4@BBf zXdm3DWTc7l1lW#y?<9*ohnDdnr@MH0x;K=<64(#OgWxP%!6G=j)d z5E@46n+Y`cuR@ObxCAG+nBy=h+j`eXOqga9aK$&9cfQ2w4_z~hp;K@n6urYrQ?$== zz{HGfvj<91$G2X-^7{y};}{W1fgj(aJQU6P9vFZ=YSf?PI} zh_sN~Zke_OYu}I=T5{exk4)~Wk|nE~bTa-NqMJ6B>?OV>$0Na82eMOR3B4fj&_oo7 zlNqO3ew@XC&kLnXi7xWa|A0u;A6J&dO%2(ig)L%(^S2_g>w$3(wrQRvNhh#}B?3T; zz(972R^!Q)3BRNhMSq`}TyQ@Pad$+n7GShJ9}|FnBYI5HV(VCYM?M`y0P%j1*?sGW zwpAeyDf0pnqWNOHPuPHTp0$D=5KHUvFtCYgJiutIcp49XFU4yN~_rla5 zm$?C^Jkd|wM*77k6AX@n1fM`|Kele8Kh!6Ll@_?#{2obul6o<*+3|zGmN`8e|GWWBQgPvZ>-Fl-?-#Bi$ z&_{rus&k)wXgFCm><`HBll?GB0e1O~i{w;C&{bjF#JW7+AcUV3e_gF&Aw;9gXb#Ut zqlbQu@Y#B{HT)P>q|moKfvYS%$4b|m?x;(AP|=9NrxRGT&R@Z>*1I zT>)N8n0@V(M8!Idg*NH)5A1?JD`fYZz ze4=OjZiAd815kh`y^`aqLw*I6GhY{rb4q3+-_tmfg8JG7V17BCG|md3B+3v|q{SCV zon%{c7aQmnp=G4%T6(hBD#kRJjBaOnb&J1!3fh) z;Vtr8XFD8Az@-XV&ymcmzCBlk91j?;HtHPXSu2)E6AEwnOyXM_Cg*Y6K?-9ru+6_A(i!ud2OksF)n z!k8{9BJXaK#tsHQ|qOD>-mfecmc`UR#7SB78qwVe%V);_j=DAG|CxX&*B6Yt8iWJNf@ zOi>E~%firrUdAM^0p1>0Q%UQXbfoA*=B5$q*!L zeyh}3!#0ANCk|g9x>+wb;A8s?#ZG*!oK_w-F&S3Gofy1{ z84{mtF)30_tZ3nPLon!2d?gi56asD$fy)OOCX+1-m;wAee*xy4V+Jj43|q>Wj@uv5 zG$wdwC^0&q&_8}D=d@e|>hqA1uOSWo^rO7~^If~-D`ysT$|m(&@x?7USYaU1N^fb9 z&sJB(6M-A{oR7MjEko_Q`j^qF4uE9F8=^6kUbXmvxvQCxyiQEYK|eh};zfS9OCw0m zBBBT7GYz#W2xnaaG#q4$rzHSq*u*Z5-cDMzXsvho5Pp-Q`RWa1M2Csfbd&y@Ds|RZ ziol}DD%Lfqdj>bl6M==Af+6@1l1xyS;j1bT_dfE(W8+>)K|gYRS*QK|gyZu#sRsYs zJD2yhPi}w!scEYU`zUD0;e`u#>JCj^q+!ik6V-cWDN6h8C&ZHU;lyK$=judqX}dUB z^fH~^dka9<8Drp(;U3)lEWa_u3OOEL>{k(KaQ%r1lE5Au%Fu7(Bz9=2>mmBSA#uNzb9y~CAy zz8ug4hpHlGhf`Jtqq*|iq9c|u>5;w8=p29qh4;|n#K6Gj_ZhD0)=OOH>AfK3Co|{y zx%M0tUE$?4lwXXsSg;dSOdc$ADn?vwQd~k~XVsLte;sRH#ydojIY6M6Wr)GHl$(LV z_o-Nv4w%`Y3-6TW)&wRC%-RdL8qb6v0va!Vc*R69yAhyB`|spPxuuz!TOzbymsnKX z6c=dt0Dbr%Pbn0h`ALMxJ;y8TQjMYMi$W987GS=G-Kj}mUlbO2s)@4k_EMIBujhhxIAx|aW@Mn{0M zNh!~RG^U@+GOpm8-JSfknoZ%qhavQWJK?5T>98dcDnMvBRb}^w+&Y(ZPS2#7)z}Ul z%UtI}@xo0)Unv0K$^`d~O+x0E$dC#{4`$CWuS>W-Xlv*DRxj^e3Onl9hQ44$p?L);Ag*nN*8erP?d1+Fn7ElBC0z(>8aM@7g!9y%o8w*0QR}!v0AKFM+zPUKFO%C01Eg z)Z_}2iHvsT0#Mn<>%e$xs3VsfOf%NHI19Hk-eY(>zpvSa0r!?);sbT#Bka zTft%82-PELN;r=xCF0Rm3OVaP%B#|23T|=p9z+~LLr%y8Q@q(^f4SOwJIl8+G z3fkrdk-&r?-N_g$z6ZVP!#)J%Z2d=2WCLITo2Y)qRHf2Vj% z=Y6$0TIi&4y~BVov2L+xEgzV#jNuag)J2Flz}(e^r# z7O)M$0SWw9F4eQtDBmpXvm;CapymzbI{qzj{dwg|6HwSjV1sbHo%aFk8hpk72XuAw z;t!~7`rwL-BB04=T9$g=buFV9yE!Wf$rV0{>?rd7{v-2Pw&cy-B!TB@Jeg+v!p&?; zIV{f&CYBXWR^o92!H;s*c9Lby8sOBH7^#Mtl7?oU2t-F-XyLTo)TSpv2dX7j-l~pe z83eV~Y7`^8#y`c8t!;FucQb;iJ#Y$pCMt}Rg7S>n4;!Ub@;nq-$Wld|rYLnbhj~Q5 zQ2$uO3@Fa#eVy$WQ}4R~(^Lc9@$uD8-#rJxXoE)EtjV;{h4kiX!(v<9Hh;Q*x| z)dN5bE_1N?UVtij^%WDm4pt9AiwR=w-wlh0Qz%&n>#k#; zuKIq=D0($hScWatoRq!go1-jtAk*g5a9YU|V7-1TquS3()4i^vK$l(D^^63g=m9|K z#|g0Rn*d&!c?uvGjW7Ufbpn0{FC-eTLJSZgW59?={6OLiq}>nT;$D5ewIMw=%q0^C zXSy(#kAY{u_2rYeF3Ah_HOs+rP7`7LQ_N$}HI{4ZD0biDLTj*LAwrOBc59Z& z5S8DI*-DK5tuOr^1I`R?ndWH~S&hSVdpv~l;&GE&#PcloJ$2||J@|i(R0JQ6Aqyk1 zWRIf(jvM&c%nh_W)*k`hm_%y>K&=&etmP8t(J`v8B0czgx<*eMlXk!`g6+TRSopP$ z-EPUKTIiX=*$iXG5>>#spEe8!7z@DvQ_LG`uQ3yRb1h>^W?|O94&FM25p#qacEqv} zEn%Jv2}SK~jAZafQNJsaD!?e))OFqggoOhFj@IQqGd7)2Y$O%0zt$o(URM10q~CRZ zg2>4?5s=CABW0Nne-mo@!6ADSzBXfX{uGV`!0M%jqb(Ia&qLM-$d_H2RKJM*gV|Lr zS;>r|BaiQxO!ZsXPXnAT7^ji^Z;LkN%;a}8 z=H4*wi$Cr$4BeRgw`G6AfTX@A1LQ7+02)K|)QbyD^7m_z^Bx?B;~$Wb;vdj0ICeq% zZy%4l0{Be;Gb9aosqe`Kg=lZSX1HDh!cHx4_XaSp(rs`Dh5u+kGx!ZI9EQ{d5>cLW z)($uyQY8)xq@~ejuxViAh5%ZE-}pb9`1e7G<~q@OCFP1sGo<<7KQgc~{?P=j4WRn* zDG!qh!^FJSs{Wt#8PLGL>oS!>6Tq}ld)%h#ZvpY|J>F~b9sCREFaEqgAYQJ=?6_cnV$@+2lF{)^n->z^tPF?_v3CST4p;LIP74;M&Z(AgHr=zAQZMJeCeYz&flb zm{UT_?&O>#`9o`3e6Iy8eQS{HIC<5eH#zDLh)zZ#7SR-0At5vR+~WKC@m9t{EsD%n z=#*1mVR7+wrcut}N_@b&qf=i&yJDdSXC991P1)jZ<27*Q&Unc6s6N{@1`4m;MDk{@ z+3ObR^x>uh8JVZ&D8DA+@e6M#;y9jiVd*b{{8tZ{tiB;cz3<#gxsodrl2oLg`Zoy} z;55!%TKa{R;3=m|rI<`E#4N50CkAY+A3I86w0UP9(A1Eac=Q?$HU#Pmb#^Kg-ZEuRn>w?lXpZJ zFV!d@0&zjs!I6i)#Pum8^IwcN9W^YKtSR6N88%xYK&&NHRPUAaav!o zZmBgyazS6LLQONMt-LRF`L5i6u-TF%^kU88*B=l^z;LfM9h&-rBuqAs6=fU>6VR?c9nS$@`#?F|CJvuUF;IQUreDB+xoO25!F(ZDFY`^=zp z%n=50{k(+ehAt0XpVjrz)5gc%m@7)pYJ~9cMBDuD7h{W3hi6{q-8jpkjtWuE9$M)S z;p;f@h@BZT$P5}bYG|G1ys+b#YP>*Wk`MG;=GwjLY6NJ$)NsPrZRmelQ%~kkw`==e z=;_5TP$_fS59U-p+7l5mJz=fkbnG23S(mFi7*PvXCCSuB+R_Ytf--duGVMfTeytRdwwe3eVz!T^w#u? z?|Xetu6nkYPx9Z2I#~3GeD>TgCm$BI<&q3|3e32mvBXyDI6!=xqzA_`p~61;nXS@U zd!kb2%EPyX`?Vrkg=IB{L6 zE%?#b)t73k$Wzx}I$qCA4F0mQQ6tA9AT8#3EH94ymy)aFm(gO)F9EJb;U#U?Kz`~ANQvPf1tX=sfYDqi6@>@=FOv}AsbB^VU%2^1Ma4PA zJ2?g9fiIc3U1M6HRdf*Ikz6^W)q7il+a5I7a=vLNlpf?pq!(3g5l-w_4Ke0JVfl@I zr}x@6aVwHPvPjd7Q8V*S5BI&aW@nU7KaLOuTfg|(kb_>KN1=OPjojmG`24N(Va>p6 zj&$<~#+1*CfChL|N8-W3r$B_lW^>!S!L1irpJy=!S>HOrvoi3o(RCd+B~!r(CEH9r zmRz6G0Dp^`R{xij1v0s&Glc%Oy5iq!1E1Ui{Ze8GI`N)0%IaC6bCVg>B8)68-+mtE0xNYTd1-)} z`#RUY@ukYc@z-Ga@G2)%bU{G%dUS$aXOQxvUnmpp@MST%36ZS&R?W9psRq7*Wdadd z5FWFM`GO_x+9Vy!c>amU+D=@%kHnh>7?JCYHP=i#OGRfjVQbV!!OyPp?@N|s#MXxRCZFm5DSQk#olf_w9<;1O#Yq6QMq5^Y+ z&yDY$FO(mxZ}JU1A5)&RC|??7l?i7~ok1*o{|CGsw7JZT%KD74L-~|q9--c>p|8%! z8VqilL0V0sBoB-Wbj~hL4rJAv5bjCZzchTd@=sNGJOE^;ZV94NU+cql zo%CloV~qqlae_gP3@D!4$2?=h~s#|L`!2ej)A=5}g= zH2l_=;nNx;6xpWd)+!K8p||73$qKoUn-GSxm<(2~m6f*6Zs{Iu20#n^$(YFrQ*?~T z?r6Osu_d%eX{|^+zp@g&yt4#o;FVI6S(;kF|eu6Ut9q)xne2h?jLx;`xh&S!7z3SULGdfVPE|UpMws^3xiv^!j7L=X7eR ztz_EisT!eSZx?RRM>^g{w_SvAq#4w;PEqpD>v{7<3P!}15)EF_7Seu6VIqWne-dH{ zZ{GW>*9)vPU)#ZCBSv2w@Lg%7r)od>^=2rBvR{?CpA?jVPzo;&vet#!WTPvuvW10Z z!Bs1>-vNbF2`aO(;zjfK+)Y#UF_ermDW3w&ic_@$%{3BvYz>ps?bL2Cc^n4AAO7Ua zc|u*P)0j^n6YoX#-O;{@n*A23STkOv5@ou`yVudC(KtG&en^kKtE(5`Ak8w@2wFJg zl+(UnYc4Ly;*$~sIia<`a%SN=jBeP=mol%-N5)G#QpcX?-B*5mWMi5z4zGdES%Nk*a_%nU(^cd-+z)k{JNw#PYgeId(x(q$x# zTKpo^xg1~0_CiA++J=)~pO5)sSMEB>eH5s8VkMJVqb+6WMqZq6WW0nfTBYZIi6B18 z8tygwX>Cx_ELYyahdBMZrgkG#M5Ec!0TJ@6i*J)G=I#c>rG8>;3x2+*{{ZS*v-`?w z-wT2qqldRP_iD-5ystxUCQF1S6?!UghXyRX+sf863aI3;R*QoLzXwa%}9N>Rm%e#GTvZ-#ra!r*BL@CVy*~zb{q40eNEU`$b)B03q+;i@Xe%t}oZ3 z;98{gW@eA<9|>-gqUJ9X`7ECKS0OBUhO(F|P$#}}yd3Mu+?+spCtmi}1_Uq1Re>iW zfE(|c_ATDL0J3D)k#@h{PoksWgu8LH*xr)h%^YRI2fT=_)oGsED2*_@wicJUg)0rI z#jp^yaS2Tlw#E-{QVZ_bmom)!dNMv;bz{m|iz=OeAmKSf|BZFBg{UVghNZ(vx(dIs zP^=$1QdnORFuTV!-1AU=qxfK02mz2|)4_g$meg-;VKiq-C-sCSS$AGn>^l<>`PFMX z^W1k!-^1G=sS2tdR5y`&{nkd)qmf=!3n~BUMq((d00Ly~&+v^!;NF0i<7wWd99p9) zvAMUa3_DiAo%E(tYq`8h%0v*eGJE!Jy%-9wM&85oOtHXza6h$Q*in=a)jlC6C6=0H zci_zN%wct^bb@*~`OD#6(EQ$_-M(v?^iY*oTub{hBV^aI@5i?ii~39Xy53Rt8z~7| zl4dDpkAf>GnFrK=0O&36blYUHX+gYh0`Gws^F!H1b&WvsjY4gXyvrEhTUYW^-wEg;-jOjuTV|k(k}v$F4Rd`x7LLV_-wVNbXdG< zA?G!FqNLc?xUKI{kkxA@y~BjV0lK3wm9dPH{JZ_Y5gv8wd-@#7%58zjtR z=vKsX?aRss%XdGaW!wd&%90^w{&(=DK`cM?>>+Flh?|$DtDK|*A_!*?~gb&Yys(&BuJxQorO02|8HTm=lZM^j%3{Yuo;?ZeQyeSa%}!5wp<>!J zJhD#%)kqF88cUD%qAX>3M0}&WB|d!Cc+9*h_qTzO*j)jw5gEr#0tf}`23sJ49v>W9 zWp8T!X!(apeG{-|dOtT7jsUp9m23Xg?+{USpV|qcn>=b9CX_V^Up`!^R?%;T{30?S zFC$ce_yk|31iF9Qem19Yb?IpFIgyk*|JPF@-7E5%H@qlI$mAep+^3krAM|A)@wMa> zN$t$LY$1pDRX;6E#ZHN@4TXR(p_-fPl7YeBcv8-m{37cquXBl7_APdsErmr`pwO^0_}C<9GZe zuLx2w3iwKjcT&xp(rENTf7N70D@fJe-enCNx*^#vF3mZ?bGAaR&#}}{oY2^32A&z@ zx5ovx$@y!2u-#<;WXaJd_lA-AJ<_Vk@^*^_pf`bQeILIjB9g=Avt?VIsa{J&;=US4 zO9+Yq{a7WwBh_?i1zb}^7j?XU@I@NlIbxGR7uSO0qPt55C#2b)3A3yeo4L-_Bxy{Kue_vX_u4GkL`MmHev z`?W}!McTF;?5N4AEL3t{b#HTI8p@HpD-x&EwCZ`Oy7nMf$CCDkWH9^*ZlEJmYufD~ zWQhAtfdUp0mGGS+_@_AO^JpRWMUFNGgOt+hU#!r>H!sDfnT4gfjZ!!qV{TuWYDk*o zhI!RAtA<+G8!!z`OFpuD zF4X%)^reXO#y#|woBQdpT>R((ln*47g-$BfK1T25a*WReX0m;bs43zF3uNAkb#%hc z$fbgokgL?I+%d0TWo!(6tPk=(UoqGv$S-YaiLXRyR-W6woMEEX`pqBdgLDva8_T@$ zj0Y@7iXdjlcqq9W!ZC5K4rC1?ke6losrQj}x5Sy9WJ&3Ts~#5&#*=<3U1m+ z%8Iy=`1gdjh{xLMX}r1+Pu(o18_uJ$B9}`l2)2?k9)l@emU6rIIe7 zt8@^Lx03+FaUgMozf{ogkUIjt)xF(B6zQu$>d}r8nbPkyR`j&Tp)pJ zrRThlk+pcCsw5!nqNc&Kqz%2+T-zk}MFLWuw_lFt9z;eyqW^rC$J1M~P{raS!(E$e z*zvljcOs?|Ah%u59c4YOpNKf{a2tnYSB(qTMmn^r+8cL8dPZg>k4VaWfQrOW)Bf`J zBbJ%6i`!Oho1PIOAHRAuRC>vW=l53XYn4>j{mrX%PM-FJWwS-?o%pfaLY&5DZ^E_? zRLnzLNFd+75ruMEKR+`dca;y}sY~m=mss;!Yt&L*Sfgbj{H}*YIDUc@$nMo`o5kJl zTO?%QQ@}z&PNkGQQ-XTmDNDu}fMQdTH6MsRc2r~sKj!Pm-If|^W5#RqB(UXw6Z%SS z@n&M-cm4Q)oXUOsY-Z#2Z8N#BNMkS76Y@Xj%RqAPA_~$1=_TIT)Bh1*hNuB ziUoASQG$~9-Mq;Nwz!G#G(1;imt&nBp`tIE7yk^r$Bb>?k$fsLB6n#B@sb_ zWOM;ad-W`OU6e_VR=Tg`fukcCu1veTJYGKsDgc~HXhap+?{cuX%9SuNn+gSDS zn1DnV^cKDNQev9}ARJ2L^%n%Xe+U4?Y%6$?Hq`e;xR7v} zo!46<6FhQfoN1NR*3BQ1^v5~WDF{p5k`){6dm38DJJigpS;iz-^8=B3uL0plDmH1! zuSqreUHESE*}IDSMJe7ph&5ml3NNyyd3Fmad3fM%n;8Cpi74%rS3|m=07HlxvC5&G z^Cqdv*qE?n+9ROQwfc9BSLVv`&fyB?<~l`y3fT*5L+plY+Is^~UA%?SARY}t{jGlL zwM&!jf9N&*1Rv`+WP}j^4tHrU0T9KwO?&qrj6X(h$O+jceR$bzKWvcK?)wKMP`I9q zP2fV?L2U9pv$6ZHS+1fJz)1cqRDr$8F8JWv2|?cqMF@UC;Xnu>95*s6GptX&f64jm zsoQCBT_jF7<>$7%-OvYTzPD5%ZYIm{<0sTtvL0-}LM)AjpMB}>ND}@7%7TG^qK@$3 z+tN4yUpv@Yuf_m?^8tWAtFPdmoQ>f$3vs|lE}DVjb>LWk`xS6C#XCDdZ}L6w=Kzpq z9IpUgU;|ic*p=QS_=+(ZC7?e2H|Obmpz4o)2Y`@%pXcoI<>kU>9toufB43 zFz`uu3={(f$BDmW**_?lvYX(YSTIep9W9~IT@Et1y%CPsHcNj{V!CcxWlo)|bl=ry zqdF!;al$u7E5 z%WP)f8g_8^c60B{0OA)0@pTw*U}S&sXH=b8co3wox#g!&)RAHK`fWYlVOO7G>7h2$ z%HA9Jf$_Xipld#3YylVw)FQQ$tXIAFT_5FS5pS>|?Xmw(`}_NE%+r(j3-~dn$=o;%t%`E)UFL2YPwTy11i5}VzGP6`ncey= z_pZlF5sSxlj|8_;c1#c@vQOoBRiuC|VDKCRtcg}Y;k@LvdmEK=FG4(j!ve66>AX29 zQ++cpf;G4iClaTxrmso2(j_;W^>)-%Y+)BEFq6m8pG$6`bwZZ8W;)Es4?25ovEFn5 zEw!OdB&GsMzvX$i)wA;)MUv5s^Xs)DBL%kC5JbJFwXC|ngO551^EI1!9 z4*vr}Tf%+<7ue|?z>Q#vYZ+=p4BUL9Drq_8uE_IVQcK;@J(rK9k%5HjLL-#G|l7s zE=K==PPYDl#DYKO{SJA(R7P+JLqQA{qHzp)7||7!>5R3(9J~P#?SZ`qP6xvV}Ethtxwc7fNTUDh=j@4oB&*%RRTkbas4CgcPbQw zg3aJ-ULmul=gxb}|@U=lc08<$gf9ekqk3eZVB zg5{yJH)Y2VHWy#ULuhwlOePyU(MJd8vBmXG6RYE!tnt=};-aR^fzffk25KnBz8D`{ z^6jWK%G9rYrnm`|8L(=>XfTfUz!`TFjCu-2(&6SCal-%=!m$l^e`UVY|2i)X2k!g> zI#M}0EZ?N21;S+oMhPInjrH4HyB}|XURVBSw;3vGl%)+2XE35;C}W%BpDHY;@HH0T zv8&PAXhDy!*l4sO+6MSCZeUx7E!N4V2N++L^>*MG2;e}(lt2w4Ol zR{#wG46yG0T4YEcwi^2pn`d`%wC@3oUGjkh>I4l=!xrM=w*rCMh9&eE-*@amuoMvc zfM+)!Lm9!3lU!DiEVy~xBAN?h0Nz*tpsnXr|=WNZ@v(f~D^D{C0SKjic~5*(zBktsa@D)7n2aEu-p zQCA6}eH%clVt!@*g3BG(j~mB*$4vnLiL34ki~#@YG|9X8xYCYPN?x9o_ydy7!`-C5 z3I#gkJurCDm{!>LH`quV9BYG#1W@fu_{J%g4eLLs{ojxC-=hN#vIhSL=?{=I|1YNp z)uFct_Wx_+@h4^QI!S!zZP+)31~>=m5XjC9ET_)&T@RQzpBWw@-4A&TQt36A6X`t* z6$UrcY~Zq(J&Yufy_s9X=5E>me51%EnC3IkV@>-1?`4t)ED6O8ILaJ$oC)i;0;t8# z7xHs})&`mojHE{!TQN6oinU+YvP+Tn-=o;e^_jWi9t6`Rh7FtJyE-Y{H8?X0;&G$+gsG?X zV{%MIU+*YUW}ZW$Smk2YX@$?#?J_gnAUh~Jwix0Fv5Sc}D{Z<~X@~WLsg;btae3<` z-Pl*dJ-PfHwM`S}B-1jxvaW2yYl+1bjkwPhf;aPvmF&AyY zNoEdO4I_2}j&7HiYbaTSd~hRK3D;iDbx#Hmz^^%4E7UQcXW_7Z6l{49MQ!;>uBhv2(5@;HPw`!RJd8>7DBH%_h->X=}$&nRcKfA4jF4%IE)ux*OSGM#*dkyEpkik|87+HpX&A5P+~VjkxnIMQiWp^hrj<6#ob9Jr{Jxuv z-(|HiiH2Gdn|-EG5054>j_;Lky~Oa#*R8ahyh1%ajt` zCioMfR1u1YYZRi#YwseX3_Ol!yLE%P);~7@==FeE{V}%h0QU*UHeWJW3{b9g-Q9~$ z9crN(fmu&=ed?{DCeS!SZVhFEKDlM#wx3m%7>2TWi239`Qrwr~wk(C|@t(~{W7PKe zinqH_?`}hkeKURq-Z9C37{HYDk8SXX!O3_;FH<)E5BAgCvCf0fTg; zRUClrcEA`<8x2C5@o0d?c1?583Eck1SPF$DOqXT7@9gVHNsdyh)%W%xgG)4Do=I3) z(bB51uC58amjB*a$B)ZamH;d#6Z{sc1Xf0wB9{QDe>?#&NRib61J{Y#T|1%HWI z|)OzgTgNjN}&#rDe z<=FzL(wMWA$NfgfzAXeIBH}0 zqOF}1bGq@-(Ae_UFv%Mu!~0|IQ7Mio1cnwyB6ndhZ`kRy?8!q53$k2*u8;DlqySMN zx!>wWYWJ<>)2~{AVr;~t+*?_M*m0~+%0V@Eu*g9ihq?WTNp-n{qJBVqgk4}37E*7@ zCd3!~Le+!(UU1aghTbJZX*<33TFvV!nKRH=_eQENK63GT&v?QdIb8TDm?P27-Q|>? z!xfs>)QIwWE#+Yy(Oy^$l9b344aU=?{RC-^HLeq!fWAm3LA;3XfS>;f-{5F9N*a*p zo+8)e&o~De&kVptv8vV^B%&|G63b5?^apYb5N=?ihvLXY3tyxv|n)=;oiK@ zEl%#+i47O#G(16cl%onSL~bLUzDcH4e_#$?&BgIAy#Kz_>fW_}dGXu7uNxe~m1-emzK& zywE(|!=x+F((Ww)Z^(2xTnv&`!wD`pzunjXdcm%LxSCMuQk3ZtgJZBzS2Nc8CRqC5 zExCOm;54BglGX;a zRQ%`z!GGJ-J7B7LpwV?S0~lvTI2#HS`U>d!U;_9c&T#~Yd+<-tZc8gaK>+y^v|tE( ztmO*FK%~z%*YsiSVB0dg;ERF;rR~rBtd>9sC_r`WfwRG(em_d5_u-ARY*c;u$MrR@ zwo{9fG9St|`Qa{O#=`S-X;bG_d^Q~T;7S20fx*fprrIYKxLb;Fa_VAo6Y7J#0Cd-Pr#X;8w;;gc85< zJCXr82^%8-j+e5s8ldw5{YX*JASu=~!4A-P3k_VAVyKffl{G?A3!;q zHff+Og$$=CT1CE7rovngxI?erqFJY3+(c`1r+kHT;LcQNm;Q-_S4xVG=Pi#U<3azY>NM zrZ_HGg?|Ibux}m(LwQ=ALWAXFy!?w#vwAL1o@Szlf{rg1e;0^TC-844_J{}Z65a?6 zy)^=~z4S{u@iHL{+v6p>mQ&(;=RHb;dSSoI!f&hPW|zG~AqA7-9-^;rlnL+^0HVrX z6*mb;aT3&Dw+!H0F3}e5(UI?bZ-jZlb=y)Rup8t-OY6(n;WlLF#m_)dv~czrTHsPJ0`h|2J_99&|*;Ey_s|Bu2_kP)B|6t~IK?-7%;*0E)?9CQ;J zj+SY+=;AXbxMKvW<=&k)t@JN%)6OjAk-Ay7=tI3^$u>!B^rf5yx2G3Kl>pI-Gj|jP zsIN&)NrR#}`R#8Mavpkc9GNnfh_*ELWa0#-atyGnXdfH3ehAvCC$fmNZsd* z>1f$vc6B_{X`@wp`plu@Qy^UO1ysJ`an3V7{H;eNKm-FYZf!t}U2MXG1RQ*mo+^g= z&?hHYo?)yz#acsiT=X0k#0drx+vuuB24Dd)oq^3q{nF<#dcW(}I>9$O5@zIP%0%-P z_HQ!EsGu7RtK^+&wuFZ@3S7S3)B>}eOP?^N-b591=I8d($7`-u-L{g-{RWQ>6H&u$ z*%)wdz2@cqVPC-yddpF2dFmr4$hBPxh(IC#%oy^`?!h$&SarGF+R*q}aa7OQSm#Q88>$itC69nJBJJriMRUpSwt8P=rYa-rs&sT^b zwte>qD+xxkj(2AJacEPSI-cX3{nQ)3u}!vuWIwlUB2)@>V?%LV?t%jM_Q^A z3CZAQn}~s&x2#Ri5pC~Yyk4zgsO7v>$%^-$8oaSc6-#4rVv+(RN&mS|!+L8JIebI77oYAxqXwEZ0_pL1oLpr>pw@1v^U1@t!qz^H+b z%j5p|cqcpT)siPZ0odeH;NxEoZG3Sqm_jC+NE|>R&mtM*EYf#vHI_k}JH@7)aq?6l z!^4-ac0Ty&+62$B%Rf`;e>D$3W6>p%GomAcKKALpItwW4ixDbF|EvC4K0&h1pP3cm zmZ#2LJ)0L+-YNlAxPpJx@bU;9TpT8JCgYt8(@W($)Rt`TCgmp`cLr}tTwpkPvV&NA zulTzxn=v1Y%?lWtzKIu(wn9)arcge*te&&wRP#xG0q-U>bYY471<$#Ts74mr0aJ!rZM@3BsfgQmUK;Z#RS9XrPQ#BS$9tYRp6 z-0X9JBGA~E>5M5fvF96VK|?tg8&!8_iucothh-X02|F9&bRCw=H3#54@Sj;RdZ&3j zT~dC6eD}!~Ws{+pdkSK^`DHNt4%TgDg((gRqz@y;xreJm=dpJ!RJ4Xx!5E86;;kGp zW+^iP6`ZJC58X7H7iSACvpbq}BZrHaRGU(g32tW z$3bFrM@fH1YMH`v`v!brx(Qce1zL>KzKEBN6MIMlovW&6NY1Ye5_iVY2N6=eH4MrS zz9b(Ws(4VF)C>I+C#axY`X6~Si2N=%QNm%2WD znKA9?1iEvO`zKyk)>!LbDUnu+piJUe4 zo)hC+r8c<}EY-n#`Socs)tMh9O>?oH(`sJI$1${8--9+*IUIYW^(>Mg^_Dcttl%S@Z}}Z{(|=Tmw;4hn(j`+QWX6&3~}ty@3Yi z`h)8MXtSJI29vKb_&Jy>u8BVue{77M;8$X$@ztJHqwcyPjl?UwJtz!x%;R$Z8Q7PM zm3hZDV!eFzD|9u|ZRc~Q5?*Dcb26I7c2tvdYDN>Fn$wELYyVU0BOh6s?Z1A&L^Plq z`>RzdNCZK_t&MbqtA$S1;)5mf+O^)3j;8KK*;NUdE)oi-S)P2ht=0b+`VD0WnJQDY z+8!sR#6^MevM_9DcHpPqrLU271fgb+*@{qA-VRD;>wWH1RY=YmnX%|`5$wQA7>f41 z(`)DDdiI*-G~K!JG2AS-;kwXpxyEvk^zvEp$3rpKA{(D<4D;InVVx#T@Zu=K{U^ve zgAZt!SwK$^Z`=ng|9Dte0d$VipsWJWMjEsI@H8RSA5y}5p}>ZD34Xu?)a!uXu3h}x zc$*SNfARARl@>rZRl2wHN3o+SRj-VF8j)5we2q$8a~e}b#SnIHuOA=XJEP&PQutKT zLBdJ+i2(Br!5HI{H=iBB+jS$JBVQSOOFasa$%%Mam1tO28K+lUSt$;|x>cPGb$5e2 z+QIA;EvI8%-vZq}cGAZ$@GR9D_rK$hKK!_0I0p<3#Fs*o@G(3@e+Y6l4?Xm$6-r(0*o2!DgL!7SngjKT&sr zGG2iN+Y)t;bSFr26#xiBuzR=h`R>t0>hA#c1$2vYMwehbhk|WiAZFMkF`-lkRswT3 zU@nuu-2!vTq8mZ(lR%;_Vaaa}Xtq&_@C5>8qJOQQizfs1bKyX#+-~Dv%ja|_8i)T< zJ_k%Eu)_iMb6Xh*N)*tMo?vbbOnV3`g{=k;Cus()q%OAL<0=m4oQV7=Ja9uB;8C@R z{AqXq8j|H_?K_}Bl9J&CqJeZk`f!S)Clk)R-h~Rg&Yd{;I=x8Q@{F$Z>r{ zAbB{XTylM-1PllxHHAGj7O;>3_JU9dITxrU=dWEllqF|wP<&BA9ry;g6OjW28w%=J zCIe`aRX&sSUBI3G%ZmzzHCI!H0ke>4dWZBjXb_;L#)9pL)&rH~Xdns*w%Y|*IpX%> zB>E56ftPjcZ{*`lAHnEcRcT)t^S;%c=e1>kzZ4OlPawn*7$UcnaXL^D^(Cdm|Teg^R9oo>5 zo4Q%ix8j$Se?0laV}5?%DPK`I#@j-0B_sj%x~&N;Uk_2vzre!61){&DvqMUF1#_6)+ATyaPI`_t#I*YQS$fNTYwAnEcmC%Kx|DCd;{h zDAFt$sw0h%8vve>_yDt?pi-f^qx+RqXn0vFsh|JXW-}E|T)uS{ z!-W+#p%V|+_gM5&iR9`mCK;r;aJ{fwWW4fd2B z$%;dX<}HV2FwvnA-);2X-&~?zbPGqYhb*I5+s4##L=^9VZuVi6-W= z_VHxZ>fkhX+mZ4GiFAkRr||}_?~S@>NSP=6 z#oC{1TbbMpqo6cKK8rEVCN2f*#H6sdJ$^()%$K1uxkM8|%hCVzj2BmkUD-*^&&@SA zde~;xJ_^Mbl+To^&}v=T7aD}2)1uEbNnMnBwR>CH zz0Tqi6{Hn1QG503Ov7CW^~%T7ZaYqoaTzIz*X7!LpXbpDiEq@nGN~orSJ6^{OQ+n4 zZ>Xw`TGcbkF+JD{_W{lFnh1(I*-w9*XHk-Nv+QyRxMb&+s(El}#!?d(8rWT4csDEY z6L{%eKj%IlVNKfGN@b61-OXzUNge?@B&s>=py}kFieH(k)UNWZ^`*6K``{=^H2@g! zvVbcz2}dacKoC6gGOO$4(jib{VN~y%x=Wt6d%cONeZDDOtlEaY{$w)~T2h=)l)wow zuobrWB+b-UyW}dt^d`TwUEL-8|8Wlf#Yy-_-%MW`*(Yzn>5IK3q?oivy?sVxhM4oF zntKHAKwJlJ?;=x= z`xgYFWb>jEO+)ok9PCmYMBCN}z5C3RHRhR625rXGsVOPfW*R?vJIfR~R3u}Fr{R2C z;$9k{YjP``!uRP)u9Xy{Z4Ui*$hs?VKG-r71p~u|PuP?<#-Ojya9~90F>t0yXgHC+ zd2IQlyWQzehz`bAqrRt4GkrRbY2cx-b2JYe38@0MSfd3=;uSdswx~`(0;|{Goy@)8 zHJ+AX{Ju>`OckD}I@i2W&txFb((i?tYbekn*ZT4Oa%33Lj${^oz#5&CqOg6+hIXKX zioRGlB?O4z7Uit2#Bkq9a$82Lp$h$!y|(&kb)YIP_`LTi8jz&%rhpfQU}C2FUnlZ5V7*Kiy=sh91y;6AGy(VN*RY$)sg*8Z)adyG7p zMa|P3$v%U9|iBF;3%EVuz|NgHd}%e2LvwuFzdgK#yU#1%-|3{%RkAfd$`L_ zIu1*~^5aSy*~{7hxY>5U1V4?8!gKj)oe^hUA+o@3=KY@!5>T=KO{4tkZ) zg^=V4{0UNoU4Uk)pWU6leLm58Gg`Oo%%3-*w!aootN`Ea)*kGC7v}Bq0#toK(OuJ> zvk$2LlRhUlQ(Kr0?_{r#Ujm_d@)fJ`JtLd`lHZQ~l^pP2NCN-NcaZZRfmURRl0Mz3 zIf~YaHaPJZkOs?Izrn{v z-Ty)@^mF(>Whj0Mk_7OlSlAzrga7rvii4v-fb0FQ5B-A+eLVf&=_-g}{q5WcAwsY+9U8(nc0g1e zYX_{DuZRYJU6J7j85qu(d<}>vK2l>+L^@HP9_&M%zF`Mi`)AW2!DBcEu8{GHmMNXF z0_u@w6iVK?bG+j%p7JYJo=WN5!Kmt{@O?AYaq{n``L{XEV6+?9KE4%BY4PTt zD1x{(j&0ix*;Fa7F5M9caap3Yckegxd%J zpmf7UhIAs1B=Pa{i>m;L?Oz|e_{YE0(O>-M*C{@su^sjawk_B?d#qvjb4~c|(xECI zm%L4GiF5eSe5_kkjCGg&h{NB&Xo@uG3SfU3F-&4I1X15{mm?HBJ>AuCzR>eHi=WU z-@qVM3if>Qr9f=Rm5=~fE!s%(G31qk^{*xr>j0#|;YtVm@D&gngA*U&b2rjmR1QLd zBqz;_4~yjsGzXv3nk_%1y$|YASz95A|7wx>{W7rY0&A;nbYP-}qO2+i8_!7xay=rA z^?D5ER<~)VI$}aAW0xLkRi|fo82VmHnfjXBTaZY7P6|4G1Jyd>Y4Y4Dr%p=2DG)1- z<^M#`PwSNJg82iu%v66F1Yv=~<_?75e*jKT0+7SPtlzpz2wcF5>Q|3o28W!aEH$Hr z2C>tKFW2o2nwr+9KE#Uao+b1w91)7AzERGMAf%iyTr{yLhk84eqK(0rcBLw2XZPbn zb?Q5?Or1-n-CQ)TP0roYVsfnD364KmEe(Y=g!Z zpVsb^kRR5`W#3q(P;D=#6|@vg{qSTDwo$zD-s@5Ubuv&+)zoPaEZ32Hbw$pcz}jJ) zuqNAqCfs!vTZ(tInUTiLYeW*|z8uyB4rb5+!9ZLR$+L#sUr;<@Y9%ulPC27vz2)G? z-&j5-ectsof1+`_$HYTJe%uErI>;g}y773`8xP#{4`0RI_L(8m>~Ukw8QoK{pWZB< zIVsTKUZS_IaF78%%6->h7nWu<|L#KVt^4p5U-i6;1rZlv`bo5|MC6Ofaor@-FI?NqQL!7b_U z41hu{+o10@d)J^gfYlH^N3qr;M-tUw-&fHvl86lK(9cR^Aj3Y7q`Hm&xD9Jfm%`NO zN?*);uaZ|E9na9+`?R+sMaARFuU_l8f&d^ha$|rL16a@;*7bk5kOp293!r0f<%R;M zzHRskT3Q16ar{A60V|xorUSNj3J7w22M|Qw`{3~T?c>!6G^*kaRU_VaW>$3Vo$)?f zDZ)N#LI;v>EvesG2(ieX)N@|2!r{~X9W&R)VfGE9oJC*k?br=Khy7;@FQs_B))o|} zv%b=Q??qmfvxLu(HKbm6Z8l6{z5RpbO3i*ru5Y<{z0l;2?>`$4UZ_l)rsPzoU80;( zau}DXhuVoxY`nA`fQ|k4&#&=^D~(T_eQ@HpvrH#0w6}%%BSjD&aB7q#PAux&QPiLhFPDH(c z8|7t#0WL*OzR#_SGauzC`=HD%y89k^q|z6N;-f>S4V;8|f}#Bqo81?wcMKL(3h`iG zh3gX8lM2W%gbGiwT8k*EiHqw5jZd+7gAzUhP((@FO5~UFy5!S%L^twICvxV(E@_ek z!PJoAw!!!nO2WUv*xI@BFUA)5zpSxk9JpDO?KG~){ycP1v4%UV9o2vJv7!IFF)`6g zHw)E#nePaNnuyw7wsTGd$zS{&1-e*xr~nb?HJ-cqe&_5+$%XgJ48{q!cbZ%Wvxc%B zZ$6I6iL`og;a&vY@ziU7tL*|X&LJd&PtcX-I;EHZDR2A?M=QJWQRr(TANbnXrowwJ zMa}&6T29`=PhlQ6uCl@X7p%lv0P4Axcc0&`nJ>TlvR0~@-*~erTgRTJd&5-L$Au6D z$~se$n04{t>E!;T{MDp&+*Jf<==l)n(&}`{(btyE zNKGgn)aSu>nOqHXm^%ioF~J$vFX+fRo1a77sT#`3d=vsV8nGYFiU_YYX3DKphp3sU z)x1pZwDozxRPdt&1Vg==ufcCTXUr+_&+|*Iv(Av&@CwvF&>$LDr<6NwryI|XX;a}t z8mb@LdDgJxX!bpaMIv0Xp(f_IjL^J0@~M26Miz$(QNsEO1MG0$yp*>UVsuMpnjiD* z5P9uGW;d?WOAL?{wq=?dg>f6RV!J?+weZ52`yTH&_8d=1p|_bAB+9oOuDU5zdTKN2 zIpe3PhkNuOiCqKy0bs|fZ97uFCBas&jjvk$ZYcjdD-uTjgBI~h1Z;sKbF>E-IYUp@ zw@?3b1GohUAusCwcv!+TT%vH2B#0h}w1LzHnpg&&o4LK)Ip&~Z3>APTPShlGMmqGm zMwQ#2?c8xo?LDC1UT0#0zM?Rbnb0Fg{w*G3n&T%!~XygHzV zhFImyJu{szZxbzeqO;zbWfxq!6`_$R6eZ-8uKJWFvA||bnFqtb#Ph@VxqMyQejL7K zEj7_?h%&$dKZRqP5y&3iFww;MVrvfVt`8oYi&op#|8Y&XWkSB8x{h}_qbsjR*@Y&B z8!~NhlkEXw;OV0nww60*gB*5>&z^VZZ7<9=$dK_J+eu2+rnihKik`61P&TeOa*YNbxKh%h3+W ziI5g?x|ez>FroL3sMFb)tl;h}f6>p$AET^lFqFg^P2jiyq=BJ{5-OS#bQemA9>c^hp?e11rFw^^+B~J&3uxkK|@nHPtnVj8;3-aT|u+mAtFsx)?Gy+DQv>aM%pn7z$DDjil^fNHUSx)tavTyHUzJ}7`f zh!`F*sKnoWUKZgo4g8D+{& zs=F!IyO^j?3Kxo}>SHYL4dUyS~Wz+!NEcs z#c6M!NK4BT_hve)Fv4Ubkd<#iQy2hIzIQ$C5MhBfUFb%wxgCWhO`Ya! z3A~^MnOK@cZEAh=QDaq1=R51)U|o|jgT5B@xe)()>ZR^}d@bj$;MH>rVU{lzg4O7I z8ct!@WY?+Q4jJW1RB=h{)F3_{gcRkmY&z6q~+Xp zLr~FiZwcc7LD@$NAW{&oaMr7;-x^WqCXQrk3o>@}!%*h)W6X@booJk+bTtO_x_;Qh6-D(Q?_ zR;!%w%!h4t$MRZzEwc;l<1?XJ>FJ(c+H?E_rySL@4e(ZD;}>+5>1Hv-WiDL(?6U`a zRzu<)ORdsWyIHead1rDE=N!XE9`QpGZ2jy=$wDJ0E`~9Mb0*db94&l4!y3Gj;V1Mz z6wJTLhe%`YaWw}KPf&@pxDTa+ZbX7;&Nx4tKWy%T?i|B<}Gw9)2+H85yRr)lOQDYCPr0$3`}U(;Vy@>8w@MeO z`4jI>nzbP)Thj@alYmF+j z#i$ogv0kuryr^|tmr%#fzehVBFmOZ|3Mhol!_w-(djoFZXy2Y;#i+3jebmm{=*yN@ zq93&Q_i;i~u|b(|S(`ZM z=6NXfnBq}054hRm0fvFoKBuKs{G6I{QT>Ub?iLpder)k>tUh&4oM;oNa%U_;&n#=W zU$(rBNUwhk#W-}&fB4wcxxxjOBt0W4W^W_Wx*_{tQ?^=AZE+F(xo(|V4GlFD!jf?Z z3yHD}?c3#@v1|#i@)Pz05hd~xLh+TSp1paR9j=0BKesk<+6>{a?YX6;&8!^WP@ z>xRDe%ty-?^gq|~+F#Vr*u0kD`8qLZe||A5DPTNyb?rH<3CX;!#BPFQP`zLiSkh*F z=3V9Xmrf)0ql@^edQFeBTvAyzZ`mA~CAT#s-(86wvyUy+d-wg9Ou_=Ty^&sx#sh%>f-2y%O~M{u z>f#dbZaGzW<@~GfQL%{2!@n@bzdm3I@RPX1t6)}u8sjz)#oBV|Ef|LVc4*Hsnmoi0 z?t{0_O29gSYE7Vw7`DnxPaLPvs{!!$q6OH|9`1mWY--YEbWlP%`--At0fa~QSJ7K! z@zN5(DCE-Iz#jP4e@XDf|1tIt1oeU_>5a`xF#hT+Y)zuX1Ua4xv}3U2Z_OiJl~)xU zAxV6JniyOw3Z=Y}eD9TBSX{_!CWCdGfBZyxiH5WM^vUy4pbaou?0Z}k5>2mNa@pKM z21_TkpaByZ>00a%>d)7gQD})URyR)Te%pHPmY6PhEI?wJ^!Pi%9?+6T$pcA`@i1JX z`RpNgRiiPQ(&g*E)V8u3em$6+<7$P_4~+MNIYpP^OkOHq#u4wPYT|lX#Vvcsl~`wH zrky!z49W|GAbm@VNtXTV+(LJUI@@eD7xV>h8x3raMQ`(45E*k{D(l&!qcwI79;8@F zu5tA7VCl!?sz!|QyXs2GF3~Pud(KL+ikE9reS_wY-)tm*L~!uMd^WRzCboBP5{*Yh zGptIS0+Y(y33$B%N$JpKGhl<}4G<-mZQt4e1LPt+na~>Ir+43vsEv7m{+1^PMmuQKp*KF)p&tmy!EZl+)VXVp_z3{ zL7S(iFk&26`G{3VOP{W>k8yKZy8s|23_H`~&ivl+YxVaL5_LX`&;>L_;Wg)_Uod#j zge96`xi^OmgU{p%GiTwK8P#mnPWe9iz*(Jzo0e3Za|F&U;ez%UMRm(?_Mx}v-Wpn& zI~ijbjW?}&g<`6d5^o(ZOi&z>dKiWkI;L4-*FHqGdtzf@ek&{$&aJGqz;pu2&;k^; z${^Tsz+uI%@)ry3lxlo^ZFO#9vn%d!m_OIfZG$|zT*y+m?fhWcqC?){3Ie&nOrV+L z58%&%DxrO1RI88rX3In)GKXCYAB`&C$(}_`Y2yZ3BHy?<6Uh|nwX!a>4Fd`q%Z_7@`4R&&EUhhdQm}Hgu$bJpsnX7C zdv;1z(Ak}B_tx>ml6TCJcc-qt@IIJ3t!xzNCyfYj@~5pt^~LN-olKA?$k&TaD1N9u z<}RXJY1SieFs-wE-SV!q;rZ(FunFqjmi9)mp{kN7KKWXJr~<GY zkJ*rF*OFr&WxRISO?mFJ$J7$c5j$16xqG?R2Mv$`;hhNXpDfLR?~;~=t?_goi?5z6UXpbfan*^UxJXk_l3Ajq2C8K_DOUJk;fIl-UU;ThU*)btjd|a zvngfbWlL4HfvF-jjfiP-a?#k)vu31%mO=Fx$(^FnvS%`V)}$l-#9w|q_%mONE7(WB z?zk;T`IZVhIv(U{@?-0_L*pJLB*bA*?(RSwc=yClkS7@5viZl9TV+WikZGAC;0Q55 zCDwai%A5B`Lx|T00w1iMh*-HV5xYQR` zT+eb%3QJ}O0wCO$YSKz=BG}g^oA5UU$K*T=Uj=L2R9kOa$bXP3&tn}^QdGZF>Ns-!A6(l&!O4MtaU_>It3pxZ8sxnHM+l`XLlOFkS zrJau}JM@$xAvFE)+A|6Qx>%|6%P8X(iKlw~_q#5=zSM-8f7E_ojy{)JB9_7t99v0yF8CtLF(nn8`GDgkb za+h?~eFwRAQHo};dJ?jHqi6Xxn)g0+-l`S*6j!aWV!yxa3_p2K^`Qza&-4+L^64W% zqrI+tX1WC&PI}}7VxGPwZsGiWDwF*l;@+yKvycbHFvGh*t2LoQ?7;xmCL-w6VSt(= zkZ$vd<0m0k2P3L3+VQtNvrA9q(bMh{&ZHCap<|3VH{ON$%0MSplVa#4vcH6|^WQhQ zAEOP>le~76I&1KKtxdgw&R_X9%%V6(p)QacqLA-csKs-8S@C=VdF&KeRk@Ly|FPD&#(74$!vaVO1>l#{IT{=wIzenrI zSiK4l#AUF0+;iTu{F60j)b+M6(sj9Bz7+a#$^8;R!)ivxxX6u%$Pk?u3w<%P{7x5c z1}$dj3YVICD95$lB!4P>{W{Y`It@7Ydkj#v#D z`BfHgYucZno4B0VNJ_!Y`uf2$`@U6`b&1WqGto8444vwO@l!WWK!AvrmySMuSa%y4 ziY97AkW@u8P@tYOND+Y~Q*A*u3Es|~IZsHWM``c+`RE>1cPa;@L9b{?{!ngY^^wez zOtEJ7?DRFYu2r^^Dwek6Dy|BWeAi`r{QSN&XKU^ttL|n(asi~w?$d_hDF1>+;{6eb z0#Q>S1=`!kT~#zxdP#?w`k_ps;sOspScbmCVeIZsn zmLIKPtnn3t7njbxhPGcS8<^oVZl3ShpKP@JG2){mJ)mAyU62j0BWfv3Hj2lmu++5} zrpk*Ji6LwF268K7-X~5@eyugPto1TX{C!A<-V3~s0O-?+B}XjtPmri6#+`WV3H*o` z>zDl8{kKCw(Fw4+TPueZgsC?7Lw*3YIY1V;@DD-j|G4&a@o%-KKZ2-Xy^dtSoSPb0 zz83WtTu<=ds_*^|SX(2BxP-CNHhy(uxH7H2NPkTsg~#+`!b+l2^ni)x2)q50i1;(I z2FvH3nR*j-h&+Upfi@ckX>T42G0Cjz`kK-Y%FXtP+Kh7TBX{4%%0;cRq=(cpCLw}B z1SV!^cd^FHBkVQRK}bX4OwmkL<4ldl5=DaW(k5(Y3ri1$Iad>EU1w_DGa>F?sXC*Z z0UT(iiHe1|sKUPene^OnyC;~$3t#&6wTvI!SN_W47!z;zygTn({H6GBd@|%{)hh(! zUK?{W6f{a9)=ZfD@zP?XEoh-9{emA?yN~4E4NXBVai&$`liY8}Gs-#(j3-*m$0MXk zk9c3rs#F53=B;CwDw(rfo;`zHgdi`kJpT}r^%PVmwmseo1d3X$abs0zBJxB>5Z?Wn z;`_1ksy!E)NP#KK>23@6-nSE(Cp?v@2}~q)(!vxm=(%-I3ckGIP^PB`dzAwAeg6|Q zyHryLlL3lS+gIjHj|M6;H?Cf-buH=J*y`%R2Ig+7^t=27!BS??1S5ZR9Ls85UW z)(mPbrL3~TyoV-I*)z-9|9bm3x%}2sAqg+wmloc)l%U+F1Y4_v*a&8jycvK=Qn+uX zErd$sOyN_T)zq;ZlisHshFYc@$LU;o=Z`UA`hv*laW10)S+La?jme^#22=x4zIv{4 zgYprV*-B5+N`*Z!Y#|EQwDtLv^g&p)T}0|OvCp3NwD1X!R6UVryslMWH!7WJ_NXd~ zj?YgJirDvxQFAbkh@_%EuKK7$VXr0xY&#IEDqf*9?&Fie8~?x-Foyu`S3K2hZ!L#X*KoZR5s#^wwgkBOAUe2fvaNK13N1v!LYA6bM5 z#)B_lO1LYyP4f=}={>Ub-T-ts@7)7{)uUt#zcJ#KR&S+0rkLVl_Ao&-Rz7;b5jsI@Wco5bQI>UC z`I${!!Dl#czzy8MYlSUF7i<1{T!8PE!@*^zA{Pl8^-|45sj9x->}pb1Oq8rI>o-*= z;$vvaKr@m-s*0yTOy+TI{nyeLLd|Tk+GM$-k?zCTn`@C0ye~dUy+VN0u9&nJwikoXp?=ES$HQcZN3kTP#oqM2Y>{!kGwv@Zr0IWfsMUuQ zYgurwL z`HN8g;^9mz`xL4VH8W*_o$?CW#vmiu2=3C9@44al0{7^YzNwTW#jyh|uNmu=rl2!_ zS>gG;b5@fmsE=Z-m;m>OC81<{nuVU1BG5@%rNaEzbktm@s4zc4zqCfEYukQydTvCf z=~ALz&V6gml=G*RYlk=zJ~-O87PkgpO8iKHS4Raf03?gEvfl#~ilD(;?aUJ@3sX8d zMTI(cJZjwPHA;#@VN<)RzF#^~8s{1QO>YhS0$A(r{VK?smF$gLcNdAdL=vKL7`|}e zS3=&j@XrOjSkgVW!2P&F;$792q_mW7(riEJL*qCK#yY)>JUE1G@`su=y%Om;@VamHeXZwJT3*NVrW4}E}X_^I{r$~-(&GLFCTkcZtquvC*pYoq6n5)o+ z5H|z%uEndJ5tjX6{f_R{3x$E##~FH?=RXyr<*x=36gWT<>D^Uu}j?ske)eq z@Y7F5uWMh|WmYfi5z4&x0g)hipW*J_s5$Q^jz?Dzw)s-jWwbSaO zPaeB>!E_NhEK_u^<2oX}rOX+r z?+>|c0-=pDQ;2P_Muz6BjEa@u1GD7M0yl0n>Av;sdo+$!`nM?c{jGm&7i{tUk6rNJ zz%KYzg}F5_!Zafj#=jG-JwQALm@r2k^(8;@k?A&nI5t}X5Lp1k5+PfEC9=?M1c)s9 z0L}_O@L!26(y&N}zY$r)RR92cKWp8A8+vWmRB{zv4}_Y+}3f5($b z@Wsph1ifqd)kTQtY2#_4!2)X>ISkSy*wDci;VrN!;K3~8evbVg59<(Fq6k|Q78nbV zv@zeJ0L>pL@~~!IjLi{)6;M%i2yXvHC8OHV9ppij{v0sgR> z3z7&pDFgsIN(YXF{g47cs4$>S0XOKMkLbmJ(r{Lo2omF@G{-RH1_Y3ZA%-KeK}kq} z4bYqEOyxwS4Zryw2exu_!g>52>fe&Q7HlO1dZ zt&7l8IkL`%!sa@AL8HS}4Oe-|_np1C3&hj01j~Q^bd5r*|4GmHUu?RUnNTehoeGQw z`6a-|vPVzClnl=OcIY2e6VAZP{s^qF5vH^Ou$65dN`w3sSxjL++mCCDI8Cuh1agD9 zl-rztr6P{kyTi7~|0xtG%3#o#OKagNF32*(_H)IWzstKK5sPRa)c<1dz2lnf)@@Pj3MkSM z5R|G^L5c_xMG*lJkq$ycnlS>>K}u|(bO8aW5$RpJ)JT`!dx`W831A4McqV>p?Y)ch2XXWjteyXEE;c^TSp9*`FWgIez`{1v%~R)QPPR_7fiq z7Bw9fG61k}EDEmG-7A^y1WUHx_C}g#)P`UDaL&vMTdvL{lDUWNL%5XgbpgHOna8@C z>=I}B2}%Y)m$vdPb-EYequwiBd%NlnQK;`Xj~&3SfA&%qem9}r{Dg5jws1OsY>J4|pBTS#CZ(iMr-W~cWxQSw3FX(ibZmT`Pi*tkDUO(<5i6c&;2h44 zxC%D4HD}uyQryI5+aR)HdaKi>VRW7T!br({K{#ABqnVM{;DkRGIWZ_BTE zY7bHq>*{@=r{L7mv_pB)5&Q1ar7U5l#an&-zDY~@Q5OQk(yEk!*?C2bIl_=&Y}uzi zRyN#f^+;Gwa$=Bp#ErvUb^=+jaM70M#j&*6ir$UAk1`I1B{DlTB_-*oCR2kvV2bVg z(J_^f`6&PBZytipzOIK47pr_Z!B0t1t-S8QqRe#dPSp`OlvYltQWUd17G(2Sh`&rP zJ99t?SLaJ8a4k5+16))HWnzh1IXlfz`xWFLTYC z!0w+GDyCazT0LSs5<1sC7w1#Km^s=bL<;PiIcYI;K}1i{E}iMbU9bJe_TLHp+@NT> z>AC3sPHa|{;iC$s#ao7(S6|O0?A89`PiXaU#YO#njp?wQnL1HwsW2JM!WU=vgkL-5 zeP`cZ%8y?rGoHIRJ}@mR3Dz0c5~9!DV|01TG`Q51of}!Uskc-WR8?m(!se7$k-4d! z?uiV_>cV_>Fk|f=~aQ@)Eo<8!-iQ+Ntawq58J_tv?DTFBB@$#_S@Go#&G)@{TjP$K! zy1O7%bVpy=%Gt)`g6qp>o^V$4fYdNCc5}uqUfCmdZ2YeK_iUkjM%0B;C~`d;V)?tQ znL;}s7Q%HMP)FOp5X~mfPU+uo5IB~oSrq!XATHRdK__$Cp?IZO{%Rk>0yQK!+3zdK z>BAw|?a)p+x{y0`gR3O`Mp)0~+%tNngqyi}neYmWp{i&KN6H82eCRSGhPjT_xi*Lr z2Fg}vZ=|kFi5aT$r2F1`@J>S9BTD~7`1OI0EBBk9Upz=UWW|7Io;c)FZt@-vH^3f1 z`*VMEYbc6VGt`T!mjW)(*49=@M~i3NS2cqR0xvTw%3s7k8%MIh#{m8UasG;59cx{& z=r-unsSLOm%wq_Tj#RbU3T0!sx5EDv5r>)(w%}+VATKUdwvB`vy2-l9Lt*XKHug~j zw~?Yv^=Sk?&^0A*8?_=2&c_}|f#E^JK|2Bz_D2(9(I!oOtK03eVsanGk|-#9be~=b zb^B{cDO8d7$%w%DlhZxbqN7SB=;kjki%;uCt+DR<0K6gUEvGItOo8=m2$t@%b`I%W z_@=682ABu!3qc3*O|C0?*tQobOv{-gtGtO(cD;gU1}~LWv>SIgQk4ZQArB&|^FQ`~ zd;PWL#0yPB!aEDJOCWY|RDqY&6CF$}f2XjfeI+MB5;>TI^TmIg2vC|(^4%CcUtRnp z(<$U|ws{Dz<8dJsCKhtH(4!32RsEum7N1WlkX&~It!@-`sz38Qkg1pJ_CK3qZByuZEz2ne zAunO`SYAJ^%A%u(YXKb0QOdYv9(_cBKK zOq(@rgwQml4>WpdI5xvb8k~;5Eg!mF_KDp1N01`)0;#LsNlKzhysb80ubzzU;ew7T zmvA;Wz7*xvV*L@M0Yp{Hi5#zpivd}0!|xax4G-MnFcEL$^^P=s$a_=igrbAbt?Ikp zjbm3RJliLn>6_1f7J}x^DsM!4C2kmG8T5{d*4S@TfjnNEVz`jq`vpZ=m^790JkyBd z!!})2&qe#GOO`k|=|klumjn%b@I;05O-$BU#>vFzf{|uEM%Sq5yu2X=&1?eoWqnqe zCq5p!og6@rBzHphxND@i-@qhCC%dGtssyfFWh}^3NliZJ^WrN1U{Y|TnU&wM8KF{wZHOn-|8pmPOGLDudgz@ z^aoU1e2NjFdwFK!EZ^G{e%U6?7cr)-7pkM2W(c}dD*dpA^~vjh+}YF0Gu@RuE}G!Z zw4IZboKO1>>GNu7?z>hMAG*}_r6o_Q?v*{$UD^)mwkNoFXB$%1S5U0biS=ME&k5x5 zhgJwHYFW{fU9!z-FQKJD_Na*9Bi0JJk_5hgC$8pA)T+C0&&uMi#?qUm!Rw-2->P!! z$j~i%l}&=w3_PKvT3&L})-{`r$}gUBz&DNmjB<6C|IGLaySCe@VOy20B}0YXc0~Q0 zT`eU$F*<+-=^g>RzJ2P@pt3n{;b_In@fmud5ItD9)Ca9v+qb$m-Y)Tec@#T!{Lm7a z-&QU!W^WyV!vU%M$v|B(y*JCKizp3wU;caR@jr3vQ4P|!T{Qi_B5qx%tprZYJ4A~c znOU0n5;DC?R$5&W1=OBJ$P{4l0{Ex`)UQL#p%*+=h&_0~z&TS;zOxYr=;>|cEBw>L9_jiKv zUw;3^u(EJl_ZQ6WsoeRW0J$2}KbTsUUI-=OQkvJ4s__7<;vxS{xPkcI|F0o*t5RXf zgAd74-44swAyQ+8s#eV*CBtT!GIwZh3t}u#9&%!!wmA(rdgk1KYL*O`iLJa1{*E#d8B)GVXW6l^%_lxEKb1uOFmtZw@qudzEW8m{3H!z$ zV|9tA)el8vNk-saKEBa^WY)k(E|SM<;AKRU-E;GR$oO>=@t5@1ptC`*k$dG&;0d_r z7=-t?XhAf+f&O=jhxjss{60sctHz!E?&>M}29?1G+e-l{L*|un6J6RqfY$jSUZK*& z@9Ow!HA!F-itYCza+qMUkTuZPL*|>Wz7`Z|m?wW8O~?6UFE~lza#ztjn@&>Q!*w68w=Ap) z3XBgN5K#a44?XA}Oi*y?Z$L8>+0xtv@KC16lsRMho>jSnl19oFC1qtuX({0ByJQM~ zFrg;jM>P-j!1Fh|2IXjnzJv~s$YeZ(vdVE1lwEXRYYwQQGYstvY!CNXUR&MC(8 zItBsc(CNF91rbBhM&+%Rf>*7*kC^)oEe-ocP8vE<;1E7T{h!e%OvifWZZGvvt1;<|@>&N+~=F_Z(aQ>R5oQ+fk&q zgk`tGx<>~5L5HH7tNk=Ax6#dIby{ifa3ezw{8%(^t@)|AN47X9L*)sgEuP?tDXx1G zyPV`5VLoni9PfO!cf3bV%)>czU~HkEzMV04NN;rEcy&=xNS?Ubqb$10j)htZ4;uUT z?ji+Po!GA#uchDySz$BrRtE_$W(?-n46oYrVVsTzIa3U^oG6~YLRo7$Hjg^GBf8 zZ=zf`(%$hncU}((chkMkXmQ(==P8@yEa!=WE0aN--~@RhW#LJ?pG2#8-`X}Wwy0wK zs6h9v(x@3(9s9({YyG-(H5b&1GTlEx+oFUFc?JRd82wDn8DmK>9T!Q%^k2syUw)`h zN_=R{f%0A(EpPo;5%|6xo-*3*Mp>UMTU3aU8sQqbwJ9c7OmPww;Ar!bgQE9-=eN;) zwamKo3ZP)5!9i5!XWGa&2a#%ppM0PK_G}j(pQ}^I3;pcQfse<$nAmt;-(GEes%tf| z=Uc2iq+l+JsADJ*JsfQwVz>qB7J3*klp%mK*9gy755obmB#ifG+8JRVZ}xQ=!3^G1KI7NceGqkn*YOx*uW#rZ7WR9-GxGBD;X})X z;Q^DDQP9K9k_khwixO)!Ig8sw@xtENtn$vnG6UWO!z6SxW3`ysdG$+4u~}6m?W8CN z8~+zId2j@?FtSi0Ctf|Bh5pmJ`X@?>AN1Z5*gJnWV$4|C!2cRjIuRq$? zL+*pD!67Gh3aZkOqfnP7(V7F1rV zJzO3wXd}#UXgwzK@F9_K^ue2+0&y^t!eY#|dbB~@jBD1{T*tf@w@roe@|1F|thvGx zsWq-1*AxH9j_@jXBk;S-8Wm!SpO-t1Bag#%%gF7fDT}yGXHC}!U62TBUFzjR#>kJy z7=T{uJqF_IAi56@-01_{H63xn%r#^_HHB@DApTG|Z2aUgSmGdSeo@aIr}Xd(pZ9;& zEuO!~5tjC_2tk{(;R<}}kB`8Dhg_XQGV=$n2p*X(()QKQN^lB&@Cok3Wy)Zf7-sS^ z^-v8brWc(L#IvG!T?i&%jD#Z7+29qW5s&6Porib4{qx-0K?V1mWp)1ctxb<0=TO3E zv`hk-wG3ywV_OH7<5@Co8M+wE7r@`^aPsPMEKM818HdEFM}m6dg`~8pEnq*ln!B=w zaLc!pTvw`%R=YZ0|LlXic96j<0=FJMWg-Li$k9ki3s_GCMo*k{)+{X76Oq&W@ZcGf zkvzqzD2Y)KbF@%qt{7&h`!+u4JsiPk))!Cy(n&sx*BKH#DX7tVG^{=$&E=Is&q@v} z6@p>$$?5A6w_{jN2jH50oa+P%RQ7By|Fm^*Y{1iiodTAo=A28JLYIY_)EfNLvRRbU z-UTYS&#AzbgUUu`g{6A6xUP)*dOU$wo(`~aG8eR;csO=6q`xZY{DmlfRAF9>{zK^@ zJLE>RAyuD)p=z4$%eP@X77}r7N~*)wFUD6=zK+5_1M-zTd!iWr)_01Vc}OM02S+oh zQdB7~rTXqoy?=$)DEIB11gZj4hCNU+BkDOYGCBzm+@wEDyuEC`qP7nqreFws>B^b+ z$2kADO=wzdh9lJSy5x@#wYv-Eh#4*g%D8M*QwPe1aGq~`C=tPLx<8pxOlx~M11GcQ z_J{?99DW^GHzGE{2KbTu63GuSSu-I`dICdl-+?cxY>DE8K?QZ1*XVEaDTsOHoGigF z?TE2iPy=9_(+je8>ThXZK$groMWX&YY#cYVFw$5kCiT6$U1x9 zPt#{*`M8oji?D>ixy*!6o_mie7Utwv$DpC7#nNvig&(=|;BEttnRs4|_{XW^N(yK8 zGAITpoT?6d(N*sDb6Tb%eFjm`(!B+vb*IY>$cVAKJSXn@`SXd-6!(tZTC6VhK>ItO z*pzub5R^Znx<6djZF*36#L6P?li=i=9hi1#YJtxD}OWz*C?s z9CBU0jO+#EFH{dh)){*)2EL8=#Keu?FV~UzJiwjzhCXKH%(*MPPYiQ5JS>_fKa6CC zF9&Ag*KZf6-VQPCDBc$Wa};Lk*DCMI$v)Yq#xb28PkEVo*+#g8=8at$pK1NE%d;mA zejCkn4i*v*+1tn-)P7=1-+*B6LrlEFmU{{lqBwm# zn^PX1c3msvixl1<1hYXMY70GGz@m3QxWDgx{!E<;E&k{AC6b$u`cIB*XF1fB*Dh6Jdz0}9e`snQ% z^Fw(?_x|iKR42NHU13m|+>CG=;IQA?j`BWw36W>oXnaL}Md9n*2G6pZve|HOmR zm0kO9PSKqI#VL9#@NecWAO6H3{NIbY%=}Z#g&P~{pAu~D$DVpI_|}kGb=MQc;*$pX zVO{9bku93t;(TWlJX;Y3x}Tv8Ff^Uq+2r{+fwHcIvNv^BLLupApMAL30g9!YS?IIf zuPN~pIXuU%w<#pyEqTIziS>-)d=jY0D$!Qb|P{e0kMwcoY%_76F-=xMm>s z`m`O9H;r@8uraqW2ju6ZKN_tKk3iTYmlamf1j8SxIEkb8Z=9Du)iXpMVsSE-O>~aX zJdASWm_>+k(T#ZB|05Om1*GDASY@OY!mrh4^ zkAmSL7m647d}s&YQ_AH(+6N%9YiRwFF;%6EUSY;iqBA62j&1VnY>8>Z#bYssMfvvS z;UTbQt;_^7+{)%9w<|p&E08>Q;KxSURs-$hesRv?sG7}+Nwmj=Y=foa;fT#U)=Fz@ zCRB~u2P^$|nY*L;u|m&njmGq$rUv-6A64S7jlNbcRb zvyeq3)Qw3_K90=hr+OJrdBImX>1<=$+S{+QEbF(KH*CpXv%EolI`FBE}JB7aNsvx(P zM9r-{4gzT}W4L$q#GFDASGsZ&-Q$7;nNQd6=D!u-^|Z;icFJ-XK{3Jqt?6O{ms!Rr>7{;xqWb~t^;j%-b(D4F zL`H>xYzehaSEIm(cdUFzsgV}p*Uf{Agk<04eGPnuy0SY0{((;Qz{*oDmY|+3NK4X; z;^k#G^W7o~`U=Bx67+bKnTBR&?hJdH)z`7e`h4Y_&B6QWzsko!O1E?Ji+RJx+Q!-= zhU|x6nb^l~51i}Mpl)pC~OUztyqD!DqI^V`%|ab8L35|nzD37Q z6+Ef9)2R<>u-{IosuYiN3zxHhKVMe{mzHgW@x>IXG)bvjuiEb_V&+qqbs!}M?JIgOve5NGH^~@Dn=rS}+BpuyeZUl0rN1`Ske^NP~@H#Q- zPE5?|*;~hKgCr&?VZ+hO&|pEM6wdYlwjWu^z4(M%_~3Ch>6=*Xv9OaP-hwc*FpZl> z=?{9V=c{sye;H;v*`ohg=`vboamZ^Fg)4pm8P^|pz*_sp!u?8GA*tZpQn~YuRgq*` z&xK2EWaDeRC6u-OOHp$v4bbCqz(>ptNPAwb5IIj01}j>I;08_ootbnzepdGOXRT1; zruY3%)?#R)JO?>=^D#Nq%~sbJnp6ixtXG6i9XaP^8Ul_sm4)J!rf*6=s5IO=qk3bzY~uB)w`Q{ z$|lKrLq3|c^%_Q8nja%h=Q+Q*%$bjmtzBz+Oa+pXT^@YnuuDuCI)%=vm=W^x-}{gM zsrwI*TtVG{+=Vz)vLKp-MIlQ^a)6O|^$O}kI@!_lmutT;oc?}v{b%q0R%^$Oe>o$Q zrVrzg>UKPNU0q;IP}QpS`M{`I`i0x-cR)s_;ywZQmXx%*VlV@xd!YO#J-w7YTANnk zga25l*KG=(5ZgxnsM&T5BYe&6%vk^O^vEWWXQKR|{x@Wf*7VF&QHXP~Bu>3_galZg zUcmsMI1EhjPayEVka05?QSx)h)V2^vqNB)b5Wb~QviR}wZAGy3iWfY^~ zL;<-Lh0|ggYI5lr5;>PdV}atC#yop*GOd@!k&j+pmhcj0TPk~`HXbe;eqIq)328A99gMsv^o92O1@t_ zvmar3gWN5inZFfs#w32cLUkPF{mlqoOO>IP3TGvbnfHDhv0i`2Whqtk`VNoYvX#zt zz59y$gn8O4Ctx!XnC^d}8|{ejGOvm^ti{hOUr9!dq58qfEqX8PDaTBQfv z^0}rttSWsYb!X%Lkn2Q*mxQSI6W*DWOnh6Lg-RY_;(7Uf+BGt052QOcP2_n z>4azC4AYY0&dMP#+}IL79t>ja#9s)gpd}&bnx`PKhRjt2?3b=UwuC^O(QmH)96jws zDrq3_J>XGxy96t|>f?STeM^C$-^-=xVSlo6+~x>VQ6CO_mBMLl{5i`c^_q%St3;PF z-sjgC4*GR?P40u(!$M~`v5a{%+eg5VTY|(Uvd~j94{tTGtRu<*i#yXp97izc*jJ&elfm{Gc(HYsl;HwISO*;mW6IRc2I{$u!Ks?ROqV`a-oik&VU92$+gdjX1@}~?{k!+S9YvDZkWKi z%zQCyw8U-RqEDm}opz&(=S&)|xm;c7apvO{N;-*a0lL_K>G36>Rs*xo#DTbQ8Xp^n zle$+b$Q|91m*jb+b#$*E$>O-twK6m_xH)`RjY_EFM!cC&yqT7R990Hvj1B=-0@fXA{6?e@#jRlaNIx1akwZ z5u=rGOrl#5MlxUr&>8{@mG?+uID+Uyh`>_a0r;}uXL(+{efC24m1KOz&5Ew<#G-&c zhv(bO&#(K$@!uZ58zz*wr~V4NF8F;aZjb<{1#uz{65xz@5H|xU;88z{V#%0V8hrHNcz}Z3ZKC1_*in zx2w@#o;-pu@?ahK%qraGmGH1z&BifpVJJfaTXq4d4}45d^f34wtP3CS6Z3yb$&z~@ zXgq}|p|s2o+|s4M{PA1~EN?@<%w;4mKeBoq;vJ$^=L=*GH0DJDFBVUbzODWOs1W-R zYt$&BA}1zKjv35roWvKRAmpG=|AiRc{3+%@HHrW7mpu3Wyh{DaIx(P!nj-3My&@_; zdO?1USkniKFh3evERtlNL8QlLq|SG_7Ol;NEtY-m`Gj^RBKEuqXi38qZUB zh&~4Lx?DM-C^Fli8TOc~GnR+8DM?v}U{XUp_4xXe=NGc=DuYga){bvqHiZutBTca= zCVbAGNRr`#q)dtHYGPPUvsKp;?h<4iU5`FNwad3l%C`D5rv`t3@o0%7eDDu?=GTWg^CDIX3u+^x_LVu??-QV7$ z!@01+mQQHcC3AB)62YG5v-*3)_(x9(L`TFpm@-(wu4C;aCuRV`3Yk*{lNkA^HCUpK zReF91`sRFekOUgh23;hBulJR|1M*9|Ap9fF0L~3wJmNdW!D0mQ6%?YOv|Z-CLE|z>gG@~z8Pzy}T1d5~ZKx;+{>WdvLk)8Fcp0P|G9fk#ZRI5H z-#+w9KkRJvUSJc*FHtn$Hu_e`M^SYN2Ea!GU9c)#jONT z3=4VrJH@XN0QqH<+)0XmjAqS$45l(sc>=*eyn^>iCtktcLYgPFBFs%KKI-3Xv_s8V zJ+5n3rsgrbdGOp5`Z(L$8j4RoJ(7c6(F8mW>Q$MXclT5LY7OIbDhdX9w@&>DI{(j# zYz7K^r-(p6I!FzlZMOV(Diaf2i48ytw#L74?$62}>*hST=r!7aQ~!Ykz_)83TToY} zWszFW+mtK0EUm=Tkr&jykd1Gib`^Nv|7MpmB=11*4LJ-CA#`%O0D@;M>oqNS zqi8P_ESUQ2{_T$qxJXlTz5XYyg)gKi78rJmo^Br-I*SplrJ;AJxdQA*Ca6#>O7}K{ ztfZofawYw(_QP05Mut_`Y+AO)Qn+F4Pepcxo_?pegs3%WxrEFm_4j(jmIxK$oN(@y z-Ekvhvy!;Y5~~$t6Ii?1*VWCxAx1n@fjC26yEv~HAorDBf3(@LCECHgKC2q=SwZUtiS0k^U&UH=22NVrT11yjFhZ5s3SR+Z*{Nr=|!*Y_1$QI z=B+*;_YyB-rTry1f#JugGVDty8W&tQECWujSKo0xIIFd_Aijv$9=l*C75s(M-sG#lv)3-ghB4zxWAsUdHxs;`r(%8RT`fJ z*1~k2oFf+o)0C@Zm8)UE#nED<)xr6KQhm8K@Ip1QbvSKEtIacgL^piZ{}gzGmX3qDBB(w|0PY=CI!R zd&lC{b_<}sU*1*V?cE)My53Jz%&ZwCaE^ND4i1Mj+gRFI0>7i>))jlGja&HGJTV8X z{_PSts4l6Y2goz>rw!c%0eTN#7XH!ZhuzWOu2ezBSD^*yU07gn)<-ceN5c z!#B{mr1{oZNMi60#gYu79!y2`B z)Xv_z<@`3~(1nI5TQ7;_R$R`PuAaVQqfu+K@Gqh71aS`>)HHzJqlxN&ZBe(%1?i3!t z%lDK~8?o?>Y?LI#2C>D%$%I%sB25m>qHwWX0^subS3Bl^xQWV%oL2}_(XANB3OM2w zGj1|E*zyyW)j|0SFH8hknfN!S)bE}D5@HXw@ynbsUQS3%7MTmtk(Cb4OkfvARJ3*6 z&c`N9ysD)+?DC;T88cR5YhpJJ*2a2cn?xbc$Z_=E z&bA6vVd`XKbDqJvz4Hb{3N>y>1Q2<=Az=RO6v*2_>VLjM;3hM-*VAmXg2SjJK-R$V z(`z03g6tiQYDM6qu&6#?BR+-FbhC+vnUB{$!W7GyR@Y?%KIM`=yM}R30yvT0axqIpErnn8mq9^!CltVdWigo}HYW#dbcaRfP>3I&((e1ni zR%v=AqA1dzb3G6gnbB3>gm1RtXC`#>kqD*f~`)C}>DpYV^J z@KZP1{M>8*k96a<#<(a8ep4T#hz=}Q$6j2&oSPpvBV&{`9&+YGf%n**XG49)IPZxD*A347LMAS%#R+;muPNz_%eb$8$1R7 z7@*B+N>v;Zog0KKsBVWOl^`2SoSUD|vbpb>`#!32A+l$*wQsA6ouUwjN91IZW!#Oh z5q@M=cLatbCC7N76za7x+-hP6` zUDj%R?p_=$q=y|?d^#`2Z$kM(D^|udrf=N0gQ^xZ|Mo0T~!+mbA>V_!0imGPT5U?a~41HyV7g2W)EII)!Wz`YCT^BUv9i<7xi+bVmaESz-j=(Ii>Jt%l? zPwb=Y#NuOGbPS(@Z12XF)X&tbrGGoyqv`wB$+Ft?T-X`ySjzM+KUj9F?4^PckVVgr z*-51f{^~sfJ@9ADRi(d`MTsx}Pn96D#S!cgxDZ$W2>ri50)Kmdf_sr_G=eb0|KQD` zGL;VAYhjH-kJLyJYMley7HCCR5=Vljr>dDl(vP|x-K7VoG*;GU`t4UH(Sh~E?Hwkn zuuj&)m5A|@EzaM^)!)a}-^bN|#yI|cTm_yHzmKcG;qu>b`QL1`e#7Oz;qt#oIR3vH zF8>71a@$w7#|cT88nOn=6`)dT;7E0g*^$JkyPomu#oK%SKjrM(^?w5M@(lFsM6Sur z1GMc>H^BR}J#G8v`arMB60%)nx;#M5*~S^#ds6R27?yf2)vN(U#vQ z3fthg50!s3s!LL^Fe=_!bupVc*U_p?6(g(wiA6zok^Z!fM-_ra6vM< zEJN_f!JzXm9L?`Vd=|Tt>k)P8>8Y;?^xmE&vge+m+@6y8@NB$qpEw}di5L2UrKVmk zgj-0O#wn0;DArsX>~;9CK~-)(#;#;Jyr;6+>(4Dih4B`zW8O7Ny9%gl&o5tQcVsLh zWfA1RQ*^>GC^GdU)RsWdvd!Qo*-zaIoK{T%CfcaA$4e1_gK*Dw)P{k(DB!@biIPLgm@4{nFxllN z4*($C!b9Tx&&qE?+ z{#M5MZ*D+5b`Bbfo(>4Js3^~HoBQE2hVL?$$IY&X8%;ZZVM%|+T4v^D8eNbc`w)2Z0Vk=*<@=27rTY=RnsUJD~>8U z{r#Dj#m)Gh;UMV7F)Y@Yof$_E2!o2A$fOc zE>U3cQyf^E&QK~33uune-gC|3vOU9#nalE;?SjEeA3AsfXO`+*`kBZc@j-M7hOJ`W zZ_cq(WLDiE3}4Mb8-!jieLmK=%yx%B-6eO$H2l0|X8OMH^Gdl@LrzPwhSX0S&3k-j z6^w3%LWU;c=mK%BSzm_96S@ec4`nDta$Zj5^X$ zWUv$7F;ZT*qa`RF$mnxdL`vl3-HIabJ`HweTjR5LS6|;?V2`7D_u3wB8drGhN3Gi* zR#cnnPm2sZW-4;z(`Ic^Gn zg7&4u>E%2+5JNklH-c_im+YaNY%U5^NT-v&zgp-r9NY5#sf|km?nNPn)8`xKtJ2Nt z40sSTv`Oh@=8{CSY_tt+?PvF9Co4KxsbU#;FLLjgoJy9sc&N|hvZgj?fpj&AW2UJ= zN#6lpmXUEu{6azz!E(4@n&18LaAd8kdB9Y_jXSjhHuu~$Yoj)ox+jIN)_R`8Iz>-< z7}gprtXXrss!Mn`j4Khh0AX(f1R>p0&VN-zmg`2uBwY+jb>c zrL`U3DQ3jJQpx9a!!A+~;hf%u zAtfvUy*Gz$=z7PY_kX63`0uXi&ZI1_0*~Am6YZpDKta~!nA27IiwkeTo^j+qIP6xQ zB>AIe9`A@V$RoNV+MTt?)k1k_h&*#Obc-K@2C_qP1o!vu{}Z^GBO0TJ!~@(!4V3W) zK*_dRvM#rgGm(j(3?b7a`jf!l3WbHO$pOlj2pJJiI{F`#J&4->jn&hCv47gPA&R>W zbgYj^DL_7-f|z6ewjw!>&XWf9rIuxO&`K~4mr*&kIlmS-0yW5V`#IZB{~fS|I(XLK zuCq-dDnED7=L%_7*U_QKI9qb+In93B9^LA1o0dz4KoQ1Ci(2fy1v)(RpWqYxwKPNO zI90si#Nu~~y)LU-c>p3g-$YPE;S_s@<>o@nw#JKG+Dskg#Ofcr?$>1l`l2MlF(5f_ z01(!5@P)}&a~e5^!TYVr2IMBycZzQFEO%RIEaxEq2K-N21C5s|?j#`31vUfqwliSm zy@IyYMmg3RJYvn4zQy=>y_N#6QD778m&acI)=U96EfRB>4*luJ zW^|GVpt(Y&kGAvh5o*T`)u^en5=VvVX7o>}C|JGBetKWElhKK!6>Y7~3%**3ceGVbzBE-iNEgIa%sXIz22HNaAJ4nlv4ZI-YElK{)K+DIXt_lb91matbNY% z*Evj(*xHi-Bd_?==$d$!f|A(dvX|1aHHO!}F9+kgV;-9>tZm@@^qWEB{H zAnpUqreA|;Rv_o$MaTMx$Km~=RAn{$zgEfV9?6^F4cp@q*>gd6Pe&}aQlq*w&&OVO zy7D~&&@g}Q0$k9G?-WcB%kLBcAq$#Bo=*k6(;cj%+4>IiS*!;?iI|)kxk}6P4tc=d z-`?Mste1h4B_9z5EKN=FR|LUB>kuy>>9m-VYo4IVG1+kIT)@ckM-142Xz31Xwd!Ax zL14~qi+&+9PONUR0cHB)6ad6xs*2kZ9@P@P*%j4^JtVM1zt!Us>1OebCiNOGQpW2$TrXF&zAA# zEje=@B_cB2MX|}TlUaLNL_{~*Wt&x#oL_Er$_ans=4KZRIad?oG?DdCUb-{8AbMH! z7Uq^;k}`tzy7hbMb#=PLG?Dw#x}hJ=Gf?XBEqlE^&e9*(sdzW}<)Vj44nomksMODj zFEl^jDg*7rxOP+Wrcz%LbNhpg6kbQBX@)MCL`<}PyUQcw+6NkMa{IijSQXPO)piDdl$ku zbTZakdykB1o13jt4FYs76%m%=vUu5>%8zuuZLMqGXk6Ywoyz*~mj=oy|8uh^cRII* zAV~8Knz|-x-rU&S9o|=*Q~;L2+{ef}r^WqaDv@>tq;@9$JeKN5QXv>t@Lpt}eigQmY|c4-lMY}n(NKgYq? z!=Jh|)31=fIfa=6ZQSsjiE9EPeIxb8)fi5^idl25W)7gh>z9 zMdiw_jn(~grCJf#M2m%e2nno!O2`biqw7U(vCB!%tq1h4>91dNChC({)lQ5041;D@1oa^gH#e~ixc$`)&HF$6ReWzL{;)85#*s0z`P0! zj(*;K3z8X9yb$9Si0W2?_G&B+y^L5|#*$tUED5p%Zh|TaIwZHcw7LNmY$r&e$6PrO ztEu}2{+WZ)KfC^Kbyn*6|Kr}<$@3oyi(+Cu1_?~xDH>kY+H7xhqc#%zgX6wal&Vi} zC2T+_5mN|npmhOT1RqX6GmbHyhw5DjP^U8@ClX5GRjOBq@Xb2F9&U zQiySo#wR~Dq_Wn_Dtn3Z`4Y4eRbTZP6>e%Zy}p)J!T4O}@LjP0%Fc{_+xavbvp)J( zi8Td-d5})Lk-UC)zt77+^Q*@L{POCr=JQn_m+j1)Ut5?c_Q)ziCX=!{9#uH=Md5I& zCi^?u*?Fy_l*6xu+em(Kd3)WPhnA%$LE>d;{_39U(=fiM@XZXw{%&=i(^dvD;S#SwgXjxcZ)n8^yRo~FFST9N)RD!e$&Xwjf|q<`Cs*md{r$jFT@VDOXc$`hi* z8$0SFR2!nq6Vp?QuuLYDjcpPtor=PX>Y5}p6d#@X&ofd*>VhuGX_Q~MKEeOQ;mjf%86s^0|Pj1Z|Jxk2qjW_`mI5{T*}DT z2T1HJ#8;rUWt(zN|^a_6BB? z9HyuH1r$mt+akZ(kp8Q_!T;G&XZ9Ih?kI#Zz)Nks3(m-Qr#Fby18U!W}0&b<67l$X0PLU#(Wu;d@Dm`vk%2gKO ziVG-gBe$aW%AZ<9aF+8kMcACI%X!7q;jWZwVKw9i&Or_09XB zaFCw9x_o9~IYpo*z z!WOZALs++ZdnIW+%ZVocp@CXUUxbFW?%HgzJ-bf{m7tY5x4?}{K8&GIsAm@h+{GM{ zvs|Ak&E{l9&g-fEa;22fa8oN=ODpzm|1a4LNcjsr3D+;zgz;=y=ShE&T)RMIn9~lE z;maKAZzdlInzN>#xGN8T7VnpEN8J9U#gE|(y6yU( zjzmQgp-kmiNC$^Vrjt{WO3pFmkW)iKMwo9W6iEo-&J>~?n#wU`a<0VW5SfWF4nr6Q z88c?)>vwf`-_P$!_ge4$KJT;E@3-Fd_=h#iT;J<^UDy8Xy+3_HaqucwB|@*2&e{;q9Bu^Gn-| zPm%=(%Tt7dbVdH>t<-;Mx%BUBlm6-dL&db@Gc3s4&|ayHr5*t$|C1U_AoS$3-8)gM zLNpJL@sMjh;Q4GVA$bDV0DO2O!# zJBM^Fdmm4oM`LV>m&>dt+pwFTnXXODvkol(0%7tG3!14EB8Oajk1Fa6GW# zB4uyY%AFKSS!T>Go<#4)&M)J~GQRm@oCZSd}eq9+U-+nzDT zp2>QpD*LoNO53@CZfOwYpk?h`{zQ`6v8N5<=0SsRZCdt~0(o9nx+ z=EBWd)fczowjSIgbI(LtU+_!L#id+J(!2cGF3JQMwk~C~XBar%Y3=^jHIc$vKNRln zY;PsTY0Zq<>~Z|Y&ZRfgbHig#C$DuXU41h8luN4D^J|gHIf!(EXG+%N{1NNR9Yukf z@FPegNm5%|OryX|BhS%9KK7kkpp)rN`8X3LO~b5JU4Gun=|ug=S4Sme3`0QMU z?GaA>%;U)JjkmVF81gyL7ZGqGa(+uqNFtd#q;(PrSx>M2m&U-e zKaGJse`yTh;^8ky5uU@OX|GbG-ilsR5yn10i^7jE$%kII8c2b?4t^-PWx1T8-t*=i zI-9KNb(iaA8C$ug)GtLJD&;@MZ??4b*U`$^5@sOvT1n_3!bHA5&Rlc)6}&hfXYMLP z=2w*CU$RZ=uqz8jQI1a=o8DpMC%nDJ@ByzlgY$@$i@2wukATukFx&k-V-v7&2>vtF zFrdxeXC;FqM9aBlfQ4I7Mf8{IhDFo(KPr>qK{NQD>Z##C(=3p`h`ai));$}V;O!7#_<}3HO0cB{3FJn?>zA-f0e8H19R7^ z<#T+Ee*NgQ&Di@&g{Ri|-43K|8cz8Al-R~Q;DGP`vgD|R zdqC5F2>U=kBMg%H23gd=7sPW;wV^oMh?(l_b7)W?IO-Sxz8fG2HPu%E!D~o2L977q zGBj`S60<=6-|%4&yUK~Q)1G*5P{cHbW!^QvgfU8_{~gm*!UZ9;-t@h8`sdu<>w;kkXf^zn~7ON)xy(I@RyQlEsp3ZY=#f}D3W zZ(MW@^BX`P8K`;%s4k!cOWuU5;4Uzu;13`aYe5Lj;94|uwPRW4Mf_}7A8IM#*z32z zG3Cu1Gvt(3}-b6tV(uIpAL;XX187QHEfgI*mOvJseMs?+~ zp6KS+?hZN2ocfx(Qf=udO~)?qLCS$$dP=8+ZboiV?z7r%TXk44f0Mv;>Mtw*7dn=| z=zFCKaN<@_c`80^bczyd_6yikY6mt*S){0%@FB|1&Z}~zSM^tL}M=mYg@xt)n zgwCrAupOm=ekC{z3m4GP+Wm@Q{p#$4dCx*pl?uS);yPyEe#)OJ5n-8@L)+C+M|HkP zGIl#L`r^l~H*$|URyjib`I3G5B`g{9#n|-58i^Qs)+5z2+jjL7ZSuN2SFb1e4Ek-K zZJiRGzKP0qik2>Sm!KRbpXK1i^>#CdYIYvFFjeE1GunD2ua9)(j`p=K%M71x2Zx?A z8Q*Q3i&dD=LeAZ*wsW0fMHFI8<*Ld2*U$KpN0_8r{@mo*hg0K4!rfwC?ktI(z{iog>QNpKBl*>H(%uq`BbrlSW{?F=x&D*>1c{d&xrQ3oEX20!%rT+Pv4TW#X#I- z!;XdxYZ|2er3)|Tku3*w*VSrWj<4B5Ciw}Ut`Z+Kjvfq?56d(-FJX|lt7emKd?^AO z5rG=`TDf^1@j1Dd%HPAjQx3F%Roc3eNh(h@T0&&Z;qt`bC#4rQeQ;OU*{QQJCuBs( z`lK6PL8}!bJnra7NV!E?&?c@zG@*h|+lz!J7-&&!;w;y~wsK8q+TPUurCJYbyrpVI z>wJ7xiZ;CZY$ToRlHx4i3amQ`YQ5D(JI98}#mFV>W8)Z+zXX{v#Tj%SmP|?XO zJiFG+&aB5A5;<`H{4M$!i z3R7~aYR}}KV}d>;GW8PGhEi25ub(o$QW4p=$Iw_H25#10&GrbI%&1MR78=wT&e4cvW46pP_RU3U+VcDI%w3 zfhK7JQFakdFeuQ^^-tPD-*5@Tk61NI#(FbQ| zP_S{M7S}NPWK=;`s`$miG)#rU>V8wV4=hSOalEMLAFLF*%cQ7)vO8GJCDE0$hWa%%i8S;oTGdFY;4Acz?^oTts(uhB z{~3(`Zcb7clI?=O1}N|y*y}Kl3`K`7H@M$gGtE6#%r}3_v*`WejhTU-W^!~0ffx>k zvwIpB$pws--{5hjAx?Za1l|6nrc2t0E=w%yqo$3X9OxJ`RT$o z;FXQ&d~l6(!GC7JQcAr<{z_ReCQ%FDZ!}jIJ`VSSL|~lvlh;T<`45Iv!J0%MlEE5M=JGy}2&Cy=x|Yx4NWH-4u*7 zv`UyY&dfaf+a@y!2O%$O>E%z=GH12QwO>awiZjj!KJI4(430Xre)=NZ8F*<{i*>xlbyY68+Bwen z!{hPO@26I{itPn0DqdWbPCsv;V44(|VVzN4Vx|==@iN?mo+2gj^>(GdiS%1(`9-w` z3fuDrGu)PIe10n&q475fn{%1zkNw9g14pwa-c#lC&)x$E{j&i>-L$>v^^rD%7K|dX zU7dcXhfMC#O7zG|xMsA$_o3?e*nUeyoH63ula3))1W&F<0sh21_c&0Jg`qykMq{|^ z`Z&A1uZ6xaRf^wHT`Xq(nHoS@bZ4XUv6Jz1u9}KZ@Mth~aOib?6KQN7!B7z?9Ja%N zopT`vkuxb3?DzoEy?ELdbU_VwcysM-&b@&>(-Io|E5P}(_Za@H+W`whROzDk9Ot}x<`JR%%NUn@jA66s zp?Spp27dSqk*{;QqdPR1iDU(`o%;z9gg%1ksC3=4N1^%bsHQs|doP8B)yb8ggmZ`v~q%Ia$m6Iw+U z2tShf4h3kV;WLv0d=9YUq=)~I;~?Ze;LWE6R3BXUe<)fUP8d+WRed7dX%AQf%CqsF z7#Cq*Pwt!olUw}vo`&jB)ef8$;2rod%5k1YTt%jSv;Hc;+htw_&8^o1(1F9C>SGqp zc~nBCoO>PKL=WHrOZ-ht(;P^YT?i`+2bqal)y=Q^e*{hjxVsDB$o&^Yg|C__4q}_<~tYZYUZ7RqtjNz*2bbA&~8S8~7aJK;e==l7%T(mcsSp`oUrw zsZJn5T00F5pr$#fv(q8e?r|<^{0X83HBhI&80wY-xqtPyjCdr7*@T_~;RNB`uoy}O zcEW$gne!A;{v4{+z5O<(27ZcW>VV$7~^VGmI)?XfI@JX_hH()5-`EPs|P2W*=Uvz7ldd zSAv)Z@TeXMG4oKs*P_V+7H#DphNwCt70)o|Y%M1aY~-g7%p;z0Q2pF--1G!)glIlW z6A8yHVT#mEgxN*ZOf2CUPJT$#MMt4)Ek?@1BUZ-;@^dBfw?9%VbUXf$!FX&OfOSc6 z?+?q2w48Ery>Zi=_>LJ)_8}jk_LCb{6|&OAQfs!4s=hSGCP_~Aq*ojkd}w+|Slng% zbZU~wV15P8U7#5`ZHS`n0C+mf+wQ{=gc_;580u#<*rN{Utr8640>Q8zxZMqMz7l5n zAyxcnrVlKQ`~Y_YHtR+_gGk1A1kcxj8-W)_@#i zLySM?aB;mH9c`cyr&g3yYK_WcXCGw38IL@4Uw3wm^UN;K;nGq!^0-eJ-s*OGId|`u z6eZ86i5*36v_{^!=Gw|_li?!9#zc3gf1&KI zD2^-3D2z41_+1P+%zoWV4HvVcuoF$9>)O>WpIjd$=s&D}K9Artln`0BF8>xW+$$+? z*(R|gOH_UC)S#KgVSUh8M@N3hSB>D$0m3?#JzMj~AHKDfOVk2^YLa-Q%=zc<QC2}ux95>jTYu~u7+sG?OUWDb5b^M*M#7buc z%guKQ? z?ad;36@hE(nO3aUI9B5E%qCXwNmHZOJyxJ@z^%byeFe58ETI%}{+mb%+emBS7O)oI>5WTyPuRPB`nD4>*D?&#)Xz}Ex78= zkPBFoL;P4462*Yr8d!Li`u8#-UJYHSHvI*7Byb~V+gl+X5txF{LUh^J`?)}gBbnE*&Zj1kpVid$TllH2`-bA_6c36XNkPV& zkzcZ>x$RCk@wm#H@k$}~v#Cq3O4;xF4Pz&NGtC69IAT#2@W_AvS^rRENCcMZWC7nS z-MKG@CkAZA$s82z0pzYer>L(CVijr=z(ON{WPNe;E!6M}Y$rUA@IdkM^IrS)HbfRS zNgi*1$gb(vN^I@1J*820;$+LCGpjW|`o@wp7V##a8eRA!`rFZv6W|5xsjwzs{s|0V z{T*(oL$VbB5cXSg8O&@NAvz?0Szgtn^$AwTR?AF?4wG>i7w(!o&NEf(E;~B99<%Sh z^100ioP68Uil|_-qb8O366%1{q<)VrBor><4gQ^n@xeEK`7ZR!C;u63!6yB0ST~LV zSBD2=s8^(`fE5RH@I;Mtc7#4P-8K}@J@P&nwfDVgH;n!*s@!|9`*!~Y(g}3Mx@qK1 z;<;Rcgu7itc!<#?x?X$E@#)gU&K)M(6N-%=JLF|cyUT5w0T-u4y}rKxsdK4{p9$b+ zR(Zj%*MdC0GkLm$6_%5Jw3zCA-Cmy23!{U+E zMiYcuVG*{HWSzPsnmy5Qx#!l?(G+|FD=LPOTN=pODZh2<(1n{jrIl%hzVYuAODEV? zNT#VdhX?xTK~JD5hogODkG+f7_SX4wZH_%NgrO9v{u`P(4MK0@n&=O=sz`~}UXzm( zu)LdOX?8`&pASGQ>?}x+1l9|_3B0VpTm%TO1HwkA243MYk3gj;!6Gvvuxa`UjQf~C z-_f;@+i-!YPk@I;3L)8JUjcx^qs$M7cd_jaa7@p%r2uoB zM=vMz6yo=}#R%v)wh0)XX&M7o!6BpyAo=-s% z%AY>3e13T8-3+Oz!fzuposHSFtOt(V0%nP6A-GtOuj)Nh~ppyqwKL{@E0Q*#<4A5ZNght zCiV0AHD}Wf$oE+pV$(guHf=GH3CT;>P&g=X#vxW)7w&_qLGi9SO z+_&o>$Yxb}n~Id2y@r6)}WLsA5{r)K6 zsqTi=N`Q;PHiL@vhH>Bj9pb4X*@n0(P!3JMjvo((nbF}Iq1?N;Dg5+>6AS?ihLBP< zaLRy7W(!qQIzUY|6CzCoZkhI1F9|K@8gbE$z?AXn;^7&{Z~2vm3~D)b05@_)ZvqHY zyf}NsJi;Fk)#lO)$mxB+deej&OL(dzwlR;uiGK6_S-%KI)j zs+@s-P4H{QN%C}B1MGL`p?w2r`()k63kgC^elGrITJ+^&`JQxb0r-i_-(1gXU=YDrM4R#0VNa{Yw1 zcaN4E{h>%mIylNSC1xjoSw3ol2lX5M3p>a;)N7U8+wB8x#u}h%1#Z}n*ty-9NgjIj z8zuDtE+}79&|Bf&E{zgv-CX(nS5c>r4WRC~?(oU{`N@vRtPpj!Up6*uMqo0uZXzPd z0)M)g`DIqiER*8dscjajFia8Z{s64pIQ#qkuU@6B&vK1Zj(t?T( z7jbonYX?KaKKdLe`X4G87%}i-muKMAi1zWIIFD%T<~Wbc4W~Jg`C)fO1p#OCvq*eg zKDZ8Opr6G8_0RjdU*?__a>3p%JopIj6E@I4ODCX<{#h~?y)pnw?(4UjYLe4>8f9R3R*FN2ENTly^ir+H}7rm%9= z7C*fD&J%5ay7l(;|8VQ&e{t*eZxe3nYhx|?6$z6@G=;S6e!x>3R7^gYW%&);NmE88 z_AtjwC=tHMet#q#CW0i~~~^aineSFLOl>761~c6#u-Pp<8n)TlYaZOlMey8S+D z?s8?hi|?ylb-f?BZD)!0vg>+A@P_sOm&$|xGVL4wXrV4Mnz3Sw z|ESlpPwLqz!ueJv(&QaUqFt|F7iFqS*~w(KpG{bCO0E;$jon*^7Uih~_ByDk;tzDF z63%|=D=m%d@nYNUxRsUpbSd>*_^hA8r@p-SLxQd)H=DMdw!f5eETb2*gXQiTCDOX3ESaJW9gPq4g zWlj61fji=~+IwtQO1wNwF)q3$TzGfIme(=B|0m%KVy;(8JBGMVD&5xG*sCtW+f&K3 zx(`dgdj2u}#qFN%?(SQf!o`VA;tn2Px8v6p-DrM(q@eEUAzz;jE%*CoR#d1x!nWB| zunl^1(PLC$EULDHJbTl-vAjvKtdq%3-z#H~a6e{OpS$-n`WYud zgO>^@He+S6_Thw%u zIfV+F2-M-Zi_HMlH;M*k=RX4up&3sp8zE2klIns}bxvZ@hf}@ktM2u6AE??8(04`u zN;}lg1LY-R;CLfT&yEaW4)nvXRiSSwy1A#&?N2Gsa5J68eo9ua+ z#PUB*sS5Q|c>KbHadJzmnYi}q#VV2r!$48VZL4QEF${cB3}09lP_I?Zk3p{Q`?-nJ zz<&7*E~}H<<`E|Sd6)Yw^B;ZuO0^gy72`Tk-&C=?fz_{@G>=eG=DIPQLDp@BsQ`xOPr?QUB^(s#-ZhyVuCU8e(WKMamaZL7|>>*}$ z)m+I{oFsN{mF_DOLdCuekGX)Fs#obA7`0Z(or#uCkMAWY9B4SMYYh!F@#}ffJ}pKa z=rb(iH&f@}ew<;9qR+VYfEO-O|0P%8rJ+E)_N>g5M$m4^mndid?Z*sv=p_?Nsj(UF zQn}F_X=-{*US-u-?A0IR$sVPC@p;?97Y}u1iMZSr`F%Y1AA^?+XN;;p50*dkV?3kZ z2iGJTAZi9aNP Date: Sat, 21 May 2016 00:24:41 +0800 Subject: [PATCH 73/83] bug fix --- .gitignore | 1 - 30_day/gview/bmp.obj | Bin 0 -> 4292 bytes 2 files changed, 1 deletion(-) create mode 100644 30_day/gview/bmp.obj diff --git a/.gitignore b/.gitignore index f939afe..7971a7f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ *.hrb *.lst -*.obj *.map *.bim *.hrb \ No newline at end of file diff --git a/30_day/gview/bmp.obj b/30_day/gview/bmp.obj new file mode 100644 index 0000000000000000000000000000000000000000..335ca9d41246f2d6b566a74014e9c88dd0be881f GIT binary patch literal 4292 zcmZ{me{54#6vtnGFb3k@BtQnD4pS6FpL8QI1VJ~}GId)SKQ?}j*1nG7*4FkF{DBI# zL%RASivReBCML!N|IuKC#6;531yLh0i$SA8ApCGlMPs7OWHP_!zT0=-6?jS4b3XTb z&pqed+xzyI!=cRj;MwKXZbdN^^U)0bsgh0Pyh~A*;+r(3r&_7px_a%p_PpV#&ad#y z9ID1h@0gms1>b;GIbV6MWm0ZgYwmfsKR433W%I`3D^tq6V{P8S%*bSQ?=%P_dzRHV ztJ#?_GnaQ~3cEK3*x1X~SnnQ+*HV%BXOh}`8|g-7sC&C%yt1jHLOtx8tR8Neq8^S_ z9d!LNFEg@G-P_6sGneM5z4dUGwA`-tE{2i!P0qJWgLvjaw`<45w!oDOnZo$~Ay@8b zrr`37&OO?8F~`XzhNrwkeF=ptb5Hs=WCq+tUhPa&TQyWOHa14p&ZnrmJf1PM z0iSzU1==X)9f;`}4djM%7lx)nk{PJV9q;`@%~HVajt_wV0>{7G6%)l6>pBb*SMDx}`+Salen+3rxzF#+9CKwp zcQ>WaZ&~kpuCgipZSmk(zR^9m*ng(nQOvvMZFbK_`pP4Lr~fR4@fI+pugsTUku7h^ z`A5^2`Q+1k1{7?2@n9tn;g&Jj?4O z4}B~%@DS2*@pSUH?m0(kd5eKkR(;ca>yFS&%u@!Z7iN85+c-k$so65nmh{hCe)(}d z5BFsUb?$dkQ|IUiWroqY<;=KF=X}ooGnJ8i8TwWD)#=BUMf%T-!}qwRNX~yXeVPY8 zac%#GzC+Oe_s?1CADjIfpMB~^4IJ9fV%)HSPOE{DT>DiuI|1?twa|$z<-rH677jIH zIFNS@J&5m(`>)qTWzavp;5U0nDc+!o=ml>DI#JXj(QX|f>A5=*EyAEf`A0yVLAi!6qv%rM@{}NlZd+>537g0@R6*AXV@tN@O-X(h1G| z@Fq*-0eE!h2#pWk42iVCqsvHWw!*tzB2U7*QzEu5DQ1^xA zZV=JKhE?fc7~}Mq8b-9xHKa?yL`jqUUlp|w&}lH^;M7H9k+>}mnad~$9+A(ZAe9o? z03z2F0gHHbV=ZkF7|LtV&?8oV3xw_~LEZzIB$1E!Ec&8-Q}>#Iqk?i{P47 z5P2Wu0gHq}#1v%&uNZT!P)K_`-aX$&X#6l{joLM-orLj-4Ev$6oy?HNBx2tYc^l0T z`wo&KB02_w9kq9iG`Ik49mAQg3F$^~xu_x?siiBS-69m@8|1S~B0pV2E`ekv&EFsg zB;vr~`$Qr)gA^q)9po#C%m(>YBJ)8;B(fBw4C?{%6TT9pLLzHG>Lk($vO*%;LDoxT z2S`vNFM@2B$g3c9V$9V;>4=wZ+1D*XJ$xIQLlQY~4LJmIMA8&NsI#K36Ci&{mSh4ydkar}~0P?;>T0uUP z$VQN_B(fdkq(yeY!#hlita&=2o7QSN&5X51BK1)t#hj>xqwUeKvCV`l^=Q{N!?Xk4 z!I;j)nAQ+a$M{G?yeE;=Q>kb?CSo=91iQ?2q8))ivpKNdvKqRRYg2mI#BiE=67i%F zG(+MAD>7zIDLdxa@+RL(ojF$a%o7DLSJc2

      -iO|P(5qiOQDo0inOQi^a4J({pw zJ+{NL+54!ZW4A`h>4}Ha_=k-Inn7E^tevdW%-m*nx|5tv`X9`)u)0Ajtki>HJt-_L z7B`w7Zm@yo)iy_ug`*Lhk0>>=%U>#Hb><6()}rFLN40U2Rl{vw4EN$`Bat@P`Qjw3 zrwnV}6A0I74$Lo44oYT+!D1lS}2jIS)iD9I9{_r z^V%JhSyI(myw0Yn(@K(XyiThXauL%Wa)C|0z>@DogT+jdfY-K=*EZ8D&Ge!Kn(bXE zih(VPDLE`tQ^ks5oEO9GlEf;;l(S-(gcrkYA?L+_mx?iGvSOH;7sG8alNZBh+KS Date: Sat, 21 May 2016 00:30:29 +0800 Subject: [PATCH 74/83] update README --- README.md | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index cc624ad..bb6d94f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ -30dayMakeOS —— OSASK -=========== +《30天自制操作系统》中文源码 —— OSASK -《30天自制操作系统》源码中文版。自己制作一个操作系统的过程 +=========== -阅读过程会一边汉化源码,一边执行还有根据一些相关的内容进行代码的书写,欢迎大家交流。 +自己制作一个操作系统的过程,阅读过程会一边汉化源码,一边执行还有根据一些相关的内容进行代码的书写,欢迎大家交流。 运行方法,在 `tolset` 中新建一个 `run` 文件夹,把代码拷贝进去,然后根据系统版本运行 `!cons_**.bat`。 @@ -53,22 +52,3 @@ 剩下的两天用来润色加工。这两天我们来做一些之前没来得及做,但做起来既简单又有趣的内容。 -### Links - -[川合堂](http://www.imasy.org/~mone/kawaido/) - -[kawai](http://www.imasy.org/~kawai/) - -[豆瓣图书链接](http://book.douban.com/subject/11530329/) - -[OSASK计划](http://http://osask.net/) - -[OSASK wiki](http://ja.wikipedia.org/wiki/OSASK) - -[source code at sourceforge](http://zh.sourceforge.jp/projects/osask/releases/?package_id=10517) - -### 工具软件使用 - -[GNU GPL协议](http://www.gnu.org/licenses/gpl-3.0.html) - -[GNU LGPL协议](http://www.gnu.org/licenses/lgpl-3.0.html) \ No newline at end of file From d9d034cf435b0178dc44e62bb83bf1cc70a47b4a Mon Sep 17 00:00:00 2001 From: Yourtion Date: Sat, 21 May 2016 00:31:13 +0800 Subject: [PATCH 75/83] update --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index bb6d94f..c57a76b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -《30天自制操作系统》中文源码 —— OSASK - -=========== +#《30天自制操作系统》中文源码 —— OSASK 自己制作一个操作系统的过程,阅读过程会一边汉化源码,一边执行还有根据一些相关的内容进行代码的书写,欢迎大家交流。 From 438eeb5135d6d5ecb7d511aea2b445e6aa5b6a04 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Sat, 21 May 2016 00:37:05 +0800 Subject: [PATCH 76/83] Update README --- README.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/README.md b/README.md index c57a76b..2f8fb89 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,14 @@ 渡过这个痛苦的时期,第一周就该结束了。 +- [第1天:从计算机结构到汇编程序入门](https://github.com/yourtion/30dayMakeOS/releases/tag/Day01) +- [第2天:汇编语言学习与Makefile入门](https://github.com/yourtion/30dayMakeOS/releases/tag/Day02) +- [第3天:进入32位模式并导入C语言](https://github.com/yourtion/30dayMakeOS/releases/tag/Day03) +- [第4天:C语言与画面显示的练习](https://github.com/yourtion/30dayMakeOS/releases/tag/Day04) +- [第5天:结构体、文字显示与GDT/IDT初始化](https://github.com/yourtion/30dayMakeOS/releases/tag/Day05) +- [第6天:分割编译与中断处理](https://github.com/yourtion/30dayMakeOS/releases/tag/Day06) +- [第7天:FIFO与鼠标控制](https://github.com/yourtion/30dayMakeOS/releases/tag/Day07) + ### 第二周(第8天~第14天) 一周的苦战还是很有意义的,回头一看,我们就会发现自己还是斩获颇丰的。这时我们已经基本掌握了C语言的语法,连汇编语言的水平也能达到本书的要求了。 @@ -32,12 +40,28 @@ 所以这一周我们就边学习算法边慢慢地开发操作系统。不过到了这一阶段,我们就能感觉到基本上不会再受技术问题限制了。 +- [第8天:鼠标控制与32位模式切换](https://github.com/yourtion/30dayMakeOS/releases/tag/Day08) +- [第9天:内存管理](https://github.com/yourtion/30dayMakeOS/releases/tag/Day09) +- [第10天:叠加处理](https://github.com/yourtion/30dayMakeOS/releases/tag/Day10) +- [第11天:制作窗口](https://github.com/yourtion/30dayMakeOS/releases/tag/Day11) +- [第12天:定时器(1)](https://github.com/yourtion/30dayMakeOS/releases/tag/Day12) +- [第13天:定时器(2)](https://github.com/yourtion/30dayMakeOS/releases/tag/Day13) +- [第14天:高分辨率及键盘输入](https://github.com/yourtion/30dayMakeOS/releases/tag/Day14) + ### 第三周(第15天~第21天) 现在我们的技术已经相当厉害了,可以随心所欲地开发自己的操作系统了。首先是要支持多任务,然后是开发命令行窗口,之后就可以着手开发应用程序了。 到本周结束时,就算还不够完备,我们也能拿出一个可以称之为操作系统的软件了。 +- [第15天:多任务(1)](https://github.com/yourtion/30dayMakeOS/releases/tag/Day15) +- [第16天:多任务(2)](https://github.com/yourtion/30dayMakeOS/releases/tag/Day16) +- [第17天:命令行窗口](https://github.com/yourtion/30dayMakeOS/releases/tag/Day17) +- [第18天:dir命令](https://github.com/yourtion/30dayMakeOS/releases/tag/Day18) +- [第19天:应用程序](https://github.com/yourtion/30dayMakeOS/releases/tag/Day19) +- [第20天:API](https://github.com/yourtion/30dayMakeOS/releases/tag/Day20) +- [第21天:保护操作系统](https://github.com/yourtion/30dayMakeOS/releases/tag/Day21) + ### 第四周(第22天~第28天) 在这个阶段,我们可以尽情地给操作系统增加各种各样的功能,同时还可以开发出大量像模像样的应用程序来。 @@ -46,7 +70,18 @@ 对了,说起文字才想起来,正好在这个时期可以让我们的操作系统显示文字了。 +- [第22天:用C语言编写应用程序](https://github.com/yourtion/30dayMakeOS/releases/tag/Day22) +- [第23天:图形处理相关](https://github.com/yourtion/30dayMakeOS/releases/tag/Day23) +- [第24天:窗口操作](https://github.com/yourtion/30dayMakeOS/releases/tag/Day24) +- [第25天:增加命令行窗口](https://github.com/yourtion/30dayMakeOS/releases/tag/Day25) +- [第26天:为窗口移动提速](https://github.com/yourtion/30dayMakeOS/releases/tag/Day26) +- [第27天:LDT与库](https://github.com/yourtion/30dayMakeOS/releases/tag/Day27) +- [第28天:文件操作与文字显示](https://github.com/yourtion/30dayMakeOS/releases/tag/Day28) + + ### 免费赠送两天(第29天~第30天) 剩下的两天用来润色加工。这两天我们来做一些之前没来得及做,但做起来既简单又有趣的内容。 +- [第29天:压缩与简单的应用程序](https://github.com/yourtion/30dayMakeOS/releases/tag/Day29) +- [第30天:高级的应用程序](https://github.com/yourtion/30dayMakeOS/releases/tag/Day30) \ No newline at end of file From a28136d3de82237474a60400eeab2f44a04a7ef1 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Tue, 31 May 2016 18:13:22 +0800 Subject: [PATCH 77/83] bug fix --- 30_day/haribote/console.c | 97 ++++++++++++++++++++------------------- 30_day/haribote/mtask.c | 35 +++++++------- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/30_day/haribote/console.c b/30_day/haribote/console.c index e8c5c69..dddeba3 100644 --- a/30_day/haribote/console.c +++ b/30_day/haribote/console.c @@ -9,8 +9,8 @@ void console_task(struct SHEET *sheet, int memtotal) struct TASK *task = task_now(); struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; int i, *fat = (int *) memman_alloc_4k(memman, 4 * 2880); - struct CONSOLE cons; struct FILEHANDLE fhandle[8]; + struct CONSOLE cons; char cmdline[30]; unsigned char *nihongo = (char *) *((int *) 0x0fe8); @@ -133,19 +133,19 @@ void cons_putchar(struct CONSOLE *cons, int chr, char move) cons_newline(cons); } if (((cons->cur_x - 8) & 0x1f) == 0) { - break; /* 32�Ŋ���؂ꂽ��break */ + break; /*被32整除则break*/ } } - } else if (s[0] == 0x0a) { /* ���s */ + } else if (s[0] == 0x0a) { /*换行*/ cons_newline(cons); - } else if (s[0] == 0x0d) { /* ���A */ - /* �Ƃ肠�����Ȃɂ����Ȃ� */ - } else { /* ���ʂ̕��� */ + } else if (s[0] == 0x0d) { /*回车*/ + /*先不做任何操作*/ + } else { /*一般字符*/ if (cons->sht != 0) { putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1); } if (move != 0) { - /* move��0�̂Ƃ��̓J�[�\����i�߂Ȃ� */ + /* move为0时光标不后移*/ cons->cur_x += 8; if (cons->cur_x == 8 + 240) { cons_newline(cons); @@ -161,9 +161,9 @@ void cons_newline(struct CONSOLE *cons) struct SHEET *sheet = cons->sht; struct TASK *task = task_now(); if (cons->cur_y < 28 + 112) { - cons->cur_y += 16; /* ���̍s�� */ + cons->cur_y += 16; /*到下一行*/ } else { - /* �X�N���[�� */ + /*滚动*/ if (sheet != 0) { for (y = 28; y < 28 + 112; y++) { for (x = 8; x < 8 + 240; x++) { @@ -180,7 +180,7 @@ void cons_newline(struct CONSOLE *cons) } cons->cur_x = 8; if (task->langmode == 1 && task->langbyte1 != 0) { - cons->cur_x = 16; + cons->cur_x += 8; } return; } @@ -208,7 +208,7 @@ void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) cmd_mem(cons, memtotal); } else if (strcmp(cmdline, "cls") == 0 && cons->sht != 0) { cmd_cls(cons); - } else if (strcmp(cmdline, "dir") == 0 && cons->sht != 0) { + } else if ((strcmp(cmdline, "dir") == 0 || strcmp(cmdline, "ls") == 0) && cons->sht != 0) { cmd_dir(cons); } else if (strcmp(cmdline, "exit") == 0) { cmd_exit(cons, fat); @@ -218,9 +218,9 @@ void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal) cmd_ncst(cons, cmdline, memtotal); } else if (strncmp(cmdline, "langmode ", 9) == 0) { cmd_langmode(cons, cmdline); - } else if (cmdline[0] != 0) { + }else if (cmdline[0] != 0) { if (cmd_app(cons, fat, cmdline) == 0) { - /* �R�}���h�ł͂Ȃ��A�A�v���ł��Ȃ��A����ɋ�s�ł��Ȃ� */ + /*不是命令,不是应用程序,也不是空行*/ cons_putstr0(cons, "Bad command.\n\n"); } } @@ -288,9 +288,9 @@ void cmd_exit(struct CONSOLE *cons, int *fat) memman_free_4k(memman, (int) fat, 4 * 2880); io_cli(); if (cons->sht != 0) { - fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); /* 768�`1023 */ + fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768); /* 768〜1023 */ } else { - fifo32_put(fifo, task - taskctl->tasks0 + 1024); /* 1024�`2023 */ + fifo32_put(fifo, task - taskctl->tasks0 + 1024); /*1024~2023*/ } io_sti(); for (;;) { @@ -306,11 +306,11 @@ void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal) int i; sheet_slide(sht, 32, 4); sheet_updown(sht, shtctl->top); - /* �R�}���h���C���ɓ��͂��ꂽ��������A�ꕶ�����V�����R���\�[���ɓ��� */ + /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ for (i = 6; cmdline[i] != 0; i++) { fifo32_put(fifo, cmdline[i] + 256); } - fifo32_put(fifo, 10 + 256); /* Enter */ + fifo32_put(fifo, 10 + 256); /*回车键*/ cons_newline(cons); return; } @@ -320,11 +320,12 @@ void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal) struct TASK *task = open_constask(0, memtotal); struct FIFO32 *fifo = &task->fifo; int i; - /* �R�}���h���C���ɓ��͂��ꂽ��������A�ꕶ�����V�����R���\�[���ɓ��� */ + + /*将命令行输入的字符串逐字复制到新的命令行窗口中*/ for (i = 5; cmdline[i] != 0; i++) { fifo32_put(fifo, cmdline[i] + 256); } - fifo32_put(fifo, 10 + 256); /* Enter */ + fifo32_put(fifo, 10 + 256); /*回车键*/ cons_newline(cons); return; } @@ -352,19 +353,19 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) struct SHTCTL *shtctl; struct SHEET *sht; - /* �R�}���h���C������t�@�C�����𐶐� */ + /*根据命令行生成文件名*/ for (i = 0; i < 13; i++) { if (cmdline[i] <= ' ') { break; } name[i] = cmdline[i]; } - name[i] = 0; /* �Ƃ肠�����t�@�C�����̌���0�ɂ��� */ + name[i] = 0; /*暂且将文件名的后面置为0*/ - /* �t�@�C����T�� */ + /*寻找文件 */ finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224); if (finfo == 0 && name[i - 1] != '.') { - /* ���‚���Ȃ������̂Ō���".HRB"���‚��Ă�����x�T���Ă݂� */ + /*由于找不到文件,故在文件名后面加上“.hrb”后重新寻找*/ name[i ] = '.'; name[i + 1] = 'H'; name[i + 2] = 'R'; @@ -374,7 +375,7 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) } if (finfo != 0) { - /* �t�@�C�������‚������ꍇ */ + /*如果找到文件*/ appsiz = finfo->size; p = file_loadfile2(finfo->clustno, &appsiz, fat); if (appsiz >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) { @@ -384,8 +385,8 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) dathrb = *((int *) (p + 0x0014)); q = (char *) memman_alloc_4k(memman, segsiz); task->ds_base = (int) q; - set_segmdesc(task->ldt + 0, appsiz - 1, (int) p, AR_CODE32_ER + 0x60); - set_segmdesc(task->ldt + 1, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); + set_segmdesc(task->ldt + 0, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); + set_segmdesc(task->ldt + 1, segsiz - 1, (int) q, AR_DATA32_RW + 0x60); for (i = 0; i < datsiz; i++) { q[esp + i] = p[dathrb + i]; } @@ -394,11 +395,11 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) for (i = 0; i < MAX_SHEETS; i++) { sht = &(shtctl->sheets0[i]); if ((sht->flags & 0x11) == 0x11 && sht->task == task) { - /* �A�v�����J�����ςȂ��ɂ����������𔭌� */ - sheet_free(sht); /* �‚��� */ + /*找到被应用程序遗留的窗口*/ + sheet_free(sht); /*关闭*/ } } - for (i = 0; i < 8; i++) { /* �N���[�Y���ĂȂ��t�@�C�����N���[�Y */ + for (i = 0; i < 8; i++) { /*将未关闭的文件关闭*/ if (task->fhandle[i].buf != 0) { memman_free_4k(memman, (int) task->fhandle[i].buf, task->fhandle[i].size); task->fhandle[i].buf = 0; @@ -414,7 +415,7 @@ int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline) cons_newline(cons); return 1; } - /* �t�@�C�������‚���Ȃ������ꍇ */ + /*没有找到文件的情况*/ return 0; } @@ -426,8 +427,8 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4); struct SHEET *sht; struct FIFO32 *sys_fifo = (struct FIFO32 *) *((int *) 0x0fec); - int *reg = &eax + 1; /* eax�̎��̔Ԓn */ - /* �ۑ��̂��߂�PUSHAD�������ɏ��������� */ + int *reg = &eax + 1; /* eax后面的地址*/ + /*强行改写通过PUSHAD保存的值*/ /* reg[0] : EDI, reg[1] : ESI, reg[2] : EBP, reg[3] : ESP */ /* reg[4] : EBX, reg[5] : EDX, reg[6] : ECX, reg[7] : EAX */ int i; @@ -450,7 +451,7 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax); make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0); sheet_slide(sht, ((shtctl->xsize - esi) / 2) & ~3, (shtctl->ysize - edi) / 2); - sheet_updown(sht, shtctl->top); /* ���̃}�E�X�Ɠ��������ɂȂ�悤�Ɏw��F �}�E�X�͂��̏�ɂȂ� */ + sheet_updown(sht, shtctl->top); /*将窗口图层高度指定为当前鼠标所在图层的高度,鼠标移到上层*/ reg[7] = (int) sht; } else if (edx == 6) { sht = (struct SHEET *) (ebx & 0xfffffffe); @@ -466,13 +467,13 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int } } else if (edx == 8) { memman_init((struct MEMMAN *) (ebx + ds_base)); - ecx &= 0xfffffff0; /* 16�o�C�g�P�ʂ� */ + ecx &= 0xfffffff0; /*以16字节为单位*/ memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); } else if (edx == 9) { - ecx = (ecx + 0x0f) & 0xfffffff0; /* 16�o�C�g�P�ʂɐ؂�グ */ + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ reg[7] = memman_alloc((struct MEMMAN *) (ebx + ds_base), ecx); } else if (edx == 10) { - ecx = (ecx + 0x0f) & 0xfffffff0; /* 16�o�C�g�P�ʂɐ؂�グ */ + ecx = (ecx + 0x0f) & 0xfffffff0; /*以16字节为单位进位取整*/ memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); } else if (edx == 11) { sht = (struct SHEET *) (ebx & 0xfffffffe); @@ -506,7 +507,7 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int io_cli(); if (fifo32_status(&task->fifo) == 0) { if (eax != 0) { - task_sleep(task); /* FIFO����Ȃ̂ŐQ�đ҂� */ + task_sleep(task); /* FIFO为空,休眠并等待*/ } else { io_sti(); reg[7] = -1; @@ -515,32 +516,32 @@ int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int } i = fifo32_get(&task->fifo); io_sti(); - if (i <= 1 && cons->sht != 0) { /* �J�[�\���p�^�C�} */ - /* �A�v�����s���̓J�[�\�����o�Ȃ��̂ŁA���‚����͕\���p��1�𒍕����Ă��� */ - timer_init(cons->timer, &task->fifo, 1); /* ����1�� */ + if (i <= 1) { /*光标用定时器*/ + /*应用程序运行时不需要显示光标,因此总是将下次显示用的值置为1*/ + timer_init(cons->timer, &task->fifo, 1); /*下次置为1*/ timer_settime(cons->timer, 50); } - if (i == 2) { /* �J�[�\��ON */ + if (i == 2) { /*光标ON */ cons->cur_c = COL8_FFFFFF; } - if (i == 3) { /* �J�[�\��OFF */ + if (i == 3) { /*光标OFF */ cons->cur_c = -1; } - if (i == 4) { /* �R���\�[��������‚��� */ + if (i == 4) { /*只关闭命令行窗口*/ timer_cancel(cons->timer); io_cli(); - fifo32_put(sys_fifo, cons->sht - shtctl->sheets0 + 2024); /* 2024�`2279 */ + fifo32_put(sys_fifo, cons->sht - shtctl->sheets0 + 2024); /*2024~2279*/ cons->sht = 0; io_sti(); } - if (i >= 256) { /* �L�[�{�[�h�f�[�^�i�^�X�NA�o�R�j�Ȃ� */ + if (i >= 256) { /*键盘数据(通过任务A)等*/ reg[7] = i - 256; return 0; } } } else if (edx == 16) { reg[7] = (int) timer_alloc(); - ((struct TIMER *) reg[7])->flags2 = 1; /* �����L�����Z���L�� */ + ((struct TIMER *) reg[7])->flags2 = 1; /*允许自动取消*/ } else if (edx == 17) { timer_init((struct TIMER *) ebx, &task->fifo, eax + 256); } else if (edx == 18) { @@ -642,7 +643,7 @@ int *inthandler0c(int *esp) cons_putstr0(cons, "\nINT 0C :\n Stack Exception.\n"); sprintf(s, "EIP = %08X\n", esp[11]); cons_putstr0(cons, s); - return &(task->tss.esp0); /* �ُ�I�������� */ + return &(task->tss.esp0); /*强制结束程序*/ } int *inthandler0d(int *esp) @@ -653,7 +654,7 @@ int *inthandler0d(int *esp) cons_putstr0(cons, "\nINT 0D :\n General Protected Exception.\n"); sprintf(s, "EIP = %08X\n", esp[11]); cons_putstr0(cons, s); - return &(task->tss.esp0); /* �ُ�I�������� */ + return &(task->tss.esp0); /*强制结束程序*/ } void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col) diff --git a/30_day/haribote/mtask.c b/30_day/haribote/mtask.c index 14bb46e..f67b935 100644 --- a/30_day/haribote/mtask.c +++ b/30_day/haribote/mtask.c @@ -1,4 +1,4 @@ -/* �}���`�^�X�N�֌W */ +/* 多任务管理 */ #include "bootpack.h" @@ -16,7 +16,7 @@ void task_add(struct TASK *task) struct TASKLEVEL *tl = &taskctl->level[task->level]; tl->tasks[tl->running] = task; tl->running++; - task->flags = 2; /* ���쒆 */ + task->flags = 2; /*活动中*/ return; } @@ -25,39 +25,38 @@ void task_remove(struct TASK *task) int i; struct TASKLEVEL *tl = &taskctl->level[task->level]; - /* task���ǂ��ɂ��邩��T�� */ + /*寻找task所在的位置*/ for (i = 0; i < tl->running; i++) { if (tl->tasks[i] == task) { - /* �����ɂ��� */ + /*在这里 */ break; } } tl->running--; if (i < tl->now) { - tl->now--; /* �����̂ŁA��������킹�Ă��� */ + tl->now--; /*需要移动成员,要相应地处理 */ } if (tl->now >= tl->running) { - /* now���������Ȓl�ɂȂ��Ă�����A�C������ */ + /*如果now的值出现异常,则进行修正*/ tl->now = 0; } - task->flags = 1; /* �X���[�v�� */ + task->flags = 1; /* 休眠中 */ - /* ���炵 */ + /* 移动 */ for (; i < tl->running; i++) { tl->tasks[i] = tl->tasks[i + 1]; } - return; } void task_switchsub(void) { int i; - /* ��ԏ�̃��x����T�� */ + /*寻找最上层的LEVEL */ for (i = 0; i < MAX_TASKLEVELS; i++) { if (taskctl->level[i].running > 0) { - break; /* ���‚����� */ + break; /*找到了*/ } } taskctl->now_lv = i; @@ -78,6 +77,7 @@ struct TASK *task_init(struct MEMMAN *memman) struct TASK *task, *idle; struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; + taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL)); for (i = 0; i < MAX_TASKS; i++) { taskctl->tasks0[i].flags = 0; @@ -92,11 +92,11 @@ struct TASK *task_init(struct MEMMAN *memman) } task = task_alloc(); - task->flags = 2; /* ���쒆�}�[�N */ - task->priority = 2; /* 0.02�b */ - task->level = 0; /* �ō����x�� */ + task->flags = 2; /*活动中标志*/ + task->priority = 2; /* 0.02秒*/ + task->level = 0; /*最高LEVEL */ task_add(task); - task_switchsub(); /* ���x���ݒ� */ + task_switchsub(); /* LEVEL 设置*/ load_tr(task->sel); task_timer = timer_alloc(); timer_settime(task_timer, task->priority); @@ -151,8 +151,7 @@ void task_run(struct TASK *task, int level, int priority) if (priority > 0) { task->priority = priority; } - - if (task->flags == 2 && task->level != level) { + if (task->flags == 2 && task->level != level) { /*改变活动中的LEVEL */ task_remove(task); /*这里执行之后flag的值会变为1,于是下面的if语句块也会被执行*/ } @@ -161,7 +160,6 @@ void task_run(struct TASK *task, int level, int priority) task->level = level; task_add(task); } - taskctl->lv_change = 1; /*下次任务切换时检查LEVEL */ return; } @@ -183,6 +181,7 @@ void task_sleep(struct TASK *task) return; } + void task_switch(void) { struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; From b308a9e295f2b9338faeb324477c7f60df37e293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E5=AE=87=E7=BF=94?= Date: Wed, 8 Aug 2018 00:26:36 +0800 Subject: [PATCH 78/83] fix imgout BPB data error fixed #3 --- 02_day/ipl.nas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/02_day/ipl.nas b/02_day/ipl.nas index a777748..5acc52d 100644 --- a/02_day/ipl.nas +++ b/02_day/ipl.nas @@ -6,7 +6,7 @@ ; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code JMP entry - DB 0xeb, 0x4e, 0x90 + DB 0x90 DB "HELLOIPL" ; 启动扇区名称(8字节) DW 512 ; 每个扇区(sector)大小(必须512字节) DB 1 ; 簇(cluster)大小(必须为1个扇区) From 7d59920a37ab71a7648f753ca586d6cc6de56dcc Mon Sep 17 00:00:00 2001 From: sky5454 Date: Sun, 26 May 2019 21:48:38 +0800 Subject: [PATCH 79/83] Update helloos.nas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修正:“必??”改为“必须是”,"字?"改为"字节" 不知道是不是仓库主人误操作,还是git的bug? --- 01_day/helloos.nas | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/01_day/helloos.nas b/01_day/helloos.nas index e9d1e96..416b140 100644 --- a/01_day/helloos.nas +++ b/01_day/helloos.nas @@ -12,15 +12,15 @@ DW 224 ; 根目录大小(一般为224项) DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512) DB 0xf0 ; 磁盘类型(必须为0xf0) - DW 9 ; FAT的长度(必??9扇区) + DW 9 ; FAT的长度(必须是9扇区) DW 18 ; 一个磁道(track)有几个扇区(必须为18) - DW 2 ; 磁头数(必??2) + DW 2 ; 磁头数(必须是2) DD 0 ; 不使用分区,必须是0 DD 2880 ; 重写一次磁盘大小 DB 0,0,0x29 ; 意义不明(固定) DD 0xffffffff ; (可能是)卷标号码 - DB "HELLO-OS " ; 磁盘的名称(必须为11字?,不足填空格) - DB "FAT12 " ; 磁盘格式名称(必??8字?,不足填空格) + DB "HELLO-OS " ; 磁盘的名称(必须为11字节,不足填空格) + DB "FAT12 " ; 磁盘格式名称(必须是8字节,不足填空格) RESB 18 ; 先空出18字节 ; 程序主体 @@ -47,4 +47,4 @@ DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 RESB 4600 DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 - RESB 1469432 \ No newline at end of file + RESB 1469432 From 670d454b4e60fcaa9676bebb340653064db6a381 Mon Sep 17 00:00:00 2001 From: sky5454 Date: Mon, 27 May 2019 22:13:46 +0800 Subject: [PATCH 80/83] Update README.md Add HELP --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f8fb89..5a55ab5 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ 运行方法,在 `tolset` 中新建一个 `run` 文件夹,把代码拷贝进去,然后根据系统版本运行 `!cons_**.bat`。 一般都是使用 `make run` 运行代码,27天开始使用 `make run_full`。可以直接看书。 + 又或者,把tolset里的`z_tools目录` 复制到 本项目目录`30dayMakeOS`下。 ## 完成效果 @@ -84,4 +85,4 @@ 剩下的两天用来润色加工。这两天我们来做一些之前没来得及做,但做起来既简单又有趣的内容。 - [第29天:压缩与简单的应用程序](https://github.com/yourtion/30dayMakeOS/releases/tag/Day29) -- [第30天:高级的应用程序](https://github.com/yourtion/30dayMakeOS/releases/tag/Day30) \ No newline at end of file +- [第30天:高级的应用程序](https://github.com/yourtion/30dayMakeOS/releases/tag/Day30) From dade193e1fdb78fbf9b5b2b870bca8535aa19790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E5=AE=87=E7=BF=94?= Date: Mon, 10 Aug 2020 09:36:42 +0800 Subject: [PATCH 81/83] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2f8fb89..eb02440 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -#《30天自制操作系统》中文源码 —— OSASK +# 《30天自制操作系统》中文源码 —— OSASK 自己制作一个操作系统的过程,阅读过程会一边汉化源码,一边执行还有根据一些相关的内容进行代码的书写,欢迎大家交流。 @@ -84,4 +84,4 @@ 剩下的两天用来润色加工。这两天我们来做一些之前没来得及做,但做起来既简单又有趣的内容。 - [第29天:压缩与简单的应用程序](https://github.com/yourtion/30dayMakeOS/releases/tag/Day29) -- [第30天:高级的应用程序](https://github.com/yourtion/30dayMakeOS/releases/tag/Day30) \ No newline at end of file +- [第30天:高级的应用程序](https://github.com/yourtion/30dayMakeOS/releases/tag/Day30) From c462063e0b2f7bb60629f66555e1cb9209f4cade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E5=AE=87=E7=BF=94?= Date: Mon, 10 Aug 2020 09:40:14 +0800 Subject: [PATCH 82/83] Update ipl10.nas Fixed #10 --- 03_day/ipl10.nas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_day/ipl10.nas b/03_day/ipl10.nas index 7108a21..e75eaeb 100644 --- a/03_day/ipl10.nas +++ b/03_day/ipl10.nas @@ -53,7 +53,7 @@ retry: MOV BX,0 MOV DL,0x00 ; A驱动器 INT 0x13 ; 调用磁盘BIOS - JNC next ; 没出错则跳转到fin + JNC next ; 没出错则跳转到next ADD SI,1 ; 往SI加1 CMP SI,5 ; 比较SI与5 JAE error ; SI >= 5 跳转到error From 9bb71ea5ce4616802954d759e66c7daab6b12065 Mon Sep 17 00:00:00 2001 From: LJS80 <67176612+LJS08@users.noreply.github.com> Date: Mon, 19 Jun 2023 23:06:13 +0800 Subject: [PATCH 83/83] Update asmhead.nas --- 04_day/asmhead.nas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/04_day/asmhead.nas b/04_day/asmhead.nas index c5bce1b..733ef01 100644 --- a/04_day/asmhead.nas +++ b/04_day/asmhead.nas @@ -15,7 +15,7 @@ VRAM EQU 0x0ff8 ; 图像缓冲区的起始地址 ORG 0xc200 ; 这个的程序要被装载的内存地址 -; 画面モードを設定 +; 设置画面模式 MOV AL,0x13 ; VGA显卡,320x200x8bit MOV AH,0x00

      GyQ$xxyMzR=Bd_b{buLbR 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 +#include "apilib.h" + +void HariMain(void) +{ + char *buf, s[12]; + int win, timer, sec = 0, min = 0, hou = 0; + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "noodle"); + timer = api_alloctimer(); + api_inittimer(timer, 128); + for (;;) { + sprintf(s, "%5d:%02d:%02d", hou, min, sec); + api_boxfilwin(win, 28, 27, 115, 41, 7);/*白色*/ + api_putstrwin(win, 28, 27, 0, 11, s); /*黑色*/ + api_settimer(timer, 100); /* 1秒 */ + if (api_getkey(1) != 128) { + break; + } + sec++; + if (sec == 60) { + sec = 0; + min++; + if (min == 60) { + min = 0; + hou++; + } + } + } + api_end(); +} diff --git a/30_day/notrec/!cons_9x.bat b/30_day/notrec/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/notrec/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/notrec/!cons_nt.bat b/30_day/notrec/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/notrec/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/notrec/Makefile b/30_day/notrec/Makefile new file mode 100644 index 0000000..7d7d3f0 --- /dev/null +++ b/30_day/notrec/Makefile @@ -0,0 +1,5 @@ +APP = notrec +STACK = 11k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/notrec/make.bat b/30_day/notrec/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/notrec/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/notrec/notrec.c b/30_day/notrec/notrec.c new file mode 100644 index 0000000..35ae0de --- /dev/null +++ b/30_day/notrec/notrec.c @@ -0,0 +1,17 @@ +#include "apilib.h" + +void HariMain(void) +{ + int win; + char buf[150 * 70]; + win = api_openwin(buf, 150, 70, 255, "notrec"); + api_boxfilwin(win, 0, 50, 34, 69, 255); + api_boxfilwin(win, 115, 50, 149, 69, 255); + api_boxfilwin(win, 50, 30, 99, 49, 255); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/30_day/sosu/!cons_9x.bat b/30_day/sosu/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/sosu/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/sosu/!cons_nt.bat b/30_day/sosu/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/sosu/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/sosu/Makefile b/30_day/sosu/Makefile new file mode 100644 index 0000000..de7b705 --- /dev/null +++ b/30_day/sosu/Makefile @@ -0,0 +1,5 @@ +APP = sosu +STACK = 2k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/sosu/make.bat b/30_day/sosu/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/sosu/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/sosu/sosu.c b/30_day/sosu/sosu.c new file mode 100644 index 0000000..6b9a997 --- /dev/null +++ b/30_day/sosu/sosu.c @@ -0,0 +1,24 @@ +#include +#include "apilib.h" + +#define MAX 1000 + +void HariMain(void) +{ + char flag[MAX], s[8]; + int i, j; + for (i = 0; i < MAX; i++) { + flag[i] = 0; + } + for (i = 2; i < MAX; i++) { + if (flag[i] == 0) { + /*没有标记的为质数*/ + sprintf(s, "%d ", i); + api_putstr0(s); + for (j = i * 2; j < MAX; j += i) { + flag[j] = 1; /*给它的倍数做上标记*/ + } + } + } + api_end(); +} diff --git a/30_day/sosu2/!cons_9x.bat b/30_day/sosu2/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/sosu2/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/sosu2/!cons_nt.bat b/30_day/sosu2/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/sosu2/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/sosu2/Makefile b/30_day/sosu2/Makefile new file mode 100644 index 0000000..d97a733 --- /dev/null +++ b/30_day/sosu2/Makefile @@ -0,0 +1,5 @@ +APP = sosu2 +STACK = 11k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/sosu2/make.bat b/30_day/sosu2/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/sosu2/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/sosu2/sosu2.c b/30_day/sosu2/sosu2.c new file mode 100644 index 0000000..381e436 --- /dev/null +++ b/30_day/sosu2/sosu2.c @@ -0,0 +1,24 @@ +#include +#include "apilib.h" + +#define MAX 10000 + +void HariMain(void) +{ + char flag[MAX], s[8]; + int i, j; + for (i = 0; i < MAX; i++) { + flag[i] = 0; + } + for (i = 2; i < MAX; i++) { + if (flag[i] == 0) { + /*没有标记的为质数*/ + sprintf(s, "%d ", i); + api_putstr0(s); + for (j = i * 2; j < MAX; j += i) { + flag[j] = 1; /*给它的倍数做上标记*/ + } + } + } + api_end(); +} diff --git a/30_day/sosu3/!cons_9x.bat b/30_day/sosu3/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/sosu3/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/sosu3/!cons_nt.bat b/30_day/sosu3/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/sosu3/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/sosu3/Makefile b/30_day/sosu3/Makefile new file mode 100644 index 0000000..a7e9900 --- /dev/null +++ b/30_day/sosu3/Makefile @@ -0,0 +1,5 @@ +APP = sosu3 +STACK = 1k +MALLOC = 42k + +include ../app_make.txt diff --git a/30_day/sosu3/make.bat b/30_day/sosu3/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/sosu3/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/sosu3/sosu3.c b/30_day/sosu3/sosu3.c new file mode 100644 index 0000000..db4527b --- /dev/null +++ b/30_day/sosu3/sosu3.c @@ -0,0 +1,26 @@ +#include +#include "apilib.h" + +#define MAX 10000 + +void HariMain(void) +{ + char *flag, s[8]; + int i, j; + api_initmalloc(); + flag = api_malloc(MAX); + for (i = 0; i < MAX; i++) { + flag[i] = 0; + } + for (i = 2; i < MAX; i++) { + if (flag[i] == 0) { + /*没有标记的为质数*/ + sprintf(s, "%d ", i); + api_putstr0(s); + for (j = i * 2; j < MAX; j += i) { + flag[j] = 1; /*给它的倍数做上标记*/ + } + } + } + api_end(); +} diff --git a/30_day/star1/!cons_9x.bat b/30_day/star1/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/star1/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/star1/!cons_nt.bat b/30_day/star1/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/star1/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/star1/Makefile b/30_day/star1/Makefile new file mode 100644 index 0000000..ae4cd72 --- /dev/null +++ b/30_day/star1/Makefile @@ -0,0 +1,5 @@ +APP = star1 +STACK = 1k +MALLOC = 47k + +include ../app_make.txt diff --git a/30_day/star1/make.bat b/30_day/star1/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/star1/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/star1/star1.c b/30_day/star1/star1.c new file mode 100644 index 0000000..93241a8 --- /dev/null +++ b/30_day/star1/star1.c @@ -0,0 +1,18 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "star1"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + api_point(win, 75, 59, 3);/*黄色*/ + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/30_day/stars/!cons_9x.bat b/30_day/stars/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/stars/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/stars/!cons_nt.bat b/30_day/stars/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/stars/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/stars/Makefile b/30_day/stars/Makefile new file mode 100644 index 0000000..899cc8f --- /dev/null +++ b/30_day/stars/Makefile @@ -0,0 +1,5 @@ +APP = stars +STACK = 1k +MALLOC = 47k + +include ../app_make.txt diff --git a/30_day/stars/make.bat b/30_day/stars/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/stars/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/stars/stars.c b/30_day/stars/stars.c new file mode 100644 index 0000000..19c54e5 --- /dev/null +++ b/30_day/stars/stars.c @@ -0,0 +1,24 @@ +#include "apilib.h" + +int rand(void); /*产生0~32767之间的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars"); + api_boxfilwin(win, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win, x, y, 3);/*黄色*/ + } + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/30_day/stars2/!cons_9x.bat b/30_day/stars2/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/stars2/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/stars2/!cons_nt.bat b/30_day/stars2/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/stars2/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/stars2/Makefile b/30_day/stars2/Makefile new file mode 100644 index 0000000..77c18cd --- /dev/null +++ b/30_day/stars2/Makefile @@ -0,0 +1,5 @@ +APP = stars2 +STACK = 1k +MALLOC = 47k + +include ../app_make.txt diff --git a/30_day/stars2/make.bat b/30_day/stars2/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/stars2/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/stars2/stars2.c b/30_day/stars2/stars2.c new file mode 100644 index 0000000..6c63c19 --- /dev/null +++ b/30_day/stars2/stars2.c @@ -0,0 +1,25 @@ +#include "apilib.h" + +int rand(void); /*产生0~32767的随机数*/ + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(150 * 100); + win = api_openwin(buf, 150, 100, -1, "stars2"); + api_boxfilwin(win + 1, 6, 26, 143, 93, 0);/*黑色*/ + for (i = 0; i < 50; i++) { + x = (rand() % 137) + 6; + y = (rand() % 67) + 26; + api_point(win + 1, x, y, 3);/*黄色*/ + } + api_refreshwin(win, 6, 26, 144, 94); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/30_day/stdlib.h b/30_day/stdlib.h new file mode 100644 index 0000000..e55f70c --- /dev/null +++ b/30_day/stdlib.h @@ -0,0 +1,4 @@ +int putchar(int c); +void exit(int status); +int printf(char *format, ...); +void *malloc(int size); \ No newline at end of file diff --git a/30_day/stdlib/!cons_9x.bat b/30_day/stdlib/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/stdlib/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/stdlib/!cons_nt.bat b/30_day/stdlib/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/stdlib/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/stdlib/Makefile b/30_day/stdlib/Makefile new file mode 100644 index 0000000..faee897 --- /dev/null +++ b/30_day/stdlib/Makefile @@ -0,0 +1,50 @@ +OBJS_API = stdlib.obj + +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) stdlib.lib + +#库生成规则 + +stdlib.lib : Makefile $(OBJS_API) + $(GOLIB) $(OBJS_API) out:stdlib.lib + +#文件生成规则 + +%.gas : %.c ../stdlib.h Makefile + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +#命令 + +clean : + -$(DEL) *.lst + -$(DEL) *.obj + +src_only : + $(MAKE) clean + -$(DEL) stdlib.lib \ No newline at end of file diff --git a/30_day/stdlib/make.bat b/30_day/stdlib/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/stdlib/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/stdlib/stdlib.c b/30_day/stdlib/stdlib.c new file mode 100644 index 0000000..5bbeae6 --- /dev/null +++ b/30_day/stdlib/stdlib.c @@ -0,0 +1,51 @@ +#include "../apilib.h" +#include "../stdlib.h" + +#include +#include + +int putchar(int c) +{ + api_putchar(c); + return c; +} + +void exit(int status) +{ + api_end(); +} + +int printf(char *format, ...) +{ + va_list ap; + char s[1000]; + int i; + + va_start(ap, format); + i = vsprintf(s, format, ap); + api_putstr0(s); + va_end(ap); + return i; +} + +void *malloc(int size) +{ + char *p = api_malloc(size + 16); + if (p != 0) { + *((int *) p) = size; + p += 16; + } + return p; +} + +void free(void *p) +{ + char *q = p; + int size; + if (q != 0) { + q -= 16; + size = *((int *) q); + api_free(q, size + 16); + } + return; +} \ No newline at end of file diff --git a/30_day/tek/autodec_.c b/30_day/tek/autodec_.c new file mode 100644 index 0000000..4d5454b --- /dev/null +++ b/30_day/tek/autodec_.c @@ -0,0 +1,649 @@ +#include /* NULL */ +#include /* malloc, free */ +#include + +typedef unsigned char UCHAR; +typedef unsigned int UINT32; +typedef UINT32 tek_TPRB; + +static int tek_decode1(int siz, UCHAR *p, UCHAR *q); +static int tek_decode2(int siz, UCHAR *p, UCHAR *q); +static int tek_decode5(int siz, UCHAR *p, UCHAR *q); + +static unsigned int tek_getnum_s7s(UCHAR **pp) +{ + unsigned int s = 0; + UCHAR *p = *pp; + do { + s = s << 7 | *p++; + } while ((s & 1) == 0); + s >>= 1; + *pp = p; + return s; +} + +int autodecomp(int siz0, UCHAR *p0, int siz) +{ + unsigned char *b = p0, *c, *c0; + int s, i, e = 0; + if ((*(int *) &b[0x08] == 0x5341534f) && (*(int *) &b[0x0c] == 0x504d434b)) { + if (*(int *) &b[0x04] == 0x00000001) { + unsigned int t = *(int *) &b[0x00]; + e |= 1; + if (0xffffff83 <= t && t <= 0xffffff89) { + c = &b[0x10]; + s = tek_getnum_s7s(&c); + if (s + siz - 0x10 <= siz0) { + c0 = c = b + siz0 - siz; + for (i = siz - 1; i >= 0x10; i--) + c[i] = b[i]; + c += 0x10; + tek_getnum_s7s(&c); + if (t == 0xffffff83) + e = tek_decode1(siz, c0, b); + if (t == 0xffffff85) + e = tek_decode2(siz, c0, b); + if (t == 0xffffff89) + e = tek_decode5(siz, c0, b); + siz = s; + } + } + } + } + if (e) + siz |= -1; + return siz; +} + +static int tek_lzrestore_stk1(int srcsiz, UCHAR *src, int outsiz, UCHAR *q) +{ + int by, lz, cp, ds; + UCHAR *q1 = q + outsiz, *s7ptr = src, *q0 = q; + do { + if ((by = (lz = *s7ptr++) & 0x0f) == 0) + by = tek_getnum_s7s(&s7ptr); + if ((lz >>= 4) == 0) + lz = tek_getnum_s7s(&s7ptr); + do { + *q++ = *s7ptr++; + } while (--by); + if (q >= q1) + break; + do { + ds = (cp = *s7ptr++) & 0x0f; + if ((ds & 1) == 0) { + do { + ds = ds << 7 | *s7ptr++; + } while ((ds & 1) == 0); + } + ds = ~(ds >> 1); + if ((cp >>= 4) == 0) { + do { + cp = cp << 7 | *s7ptr++; + } while ((cp & 1) == 0); + cp >>= 1; + } + cp++; + if (q + ds < q0) + goto err; + if (q + cp > q1) + cp = q1 - q; + do { + *q = *(q + ds); + q++; + } while (--cp); + } while (--lz); + } while (q < q1); + return 0; +err: + return 1; +} + +static int tek_decode1(int siz, UCHAR *p, UCHAR *q) +{ + int dsiz, hed, bsiz; + UCHAR *p1 = p + siz; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (dsiz > bsiz || (hed & 0x21) != 0x01) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + if (tek_getnum_s7s(&p) != 0) + return 1; + return tek_lzrestore_stk1(p1 - p, p, dsiz, q); + } + return 0; +} + +static unsigned int tek_getnum_s7(UCHAR **pp) +{ + unsigned int s = 0, b = 0, a = 1; + UCHAR *p = *pp; + for (;;) { + s = s << 7 | *p++; + if (s & 1) + break; + a <<= 7; + b += a; + } + s >>= 1; + *pp = p; + return s + b; +} + +static int tek_lzrestore_stk2(int srcsiz, UCHAR *src, int outsiz, UCHAR *q) +{ + int cp, ds, repdis[4], i, j; + UCHAR *q1 = q + outsiz, *s7ptr = src, *q0 = q, bylz, cbylz; + for (j = 0; j < 4; j++) + repdis[j] = -1 - j; + bylz = cbylz = 0; + if (outsiz) { + if (tek_getnum_s7s(&s7ptr)) + return 1; + do { + j = 0; + do { + j++; + if (j >= 17) { + j += tek_getnum_s7s(&s7ptr); + break; + } + if (cbylz == 0) { + cbylz = 8; + bylz = *s7ptr++; + } + cbylz--; + i = bylz & 1; + bylz >>= 1; + } while (i == 0); + do { + *q++ = *s7ptr++; + } while (--j); + if (q >= q1) + break; + + j = 0; + do { + j++; + if (j >= 17) { + j += tek_getnum_s7s(&s7ptr); + break; + } + if (cbylz == 0) { + cbylz = 8; + bylz = *s7ptr++; + } + cbylz--; + i = bylz & 1; + bylz >>= 1; + } while (i == 0); + do { + i = *s7ptr++; + cp = i >> 4; + i &= 0x0f; + if ((i & 1) == 0) + i |= (tek_getnum_s7(&s7ptr) + 1) << 4; + i >>= 1; + ds = ~(i - 6); + if (i < 4) + ds = repdis[i]; + if (i == 4) + ds = repdis[0] - tek_getnum_s7(&s7ptr) - 1; + if (i == 5) + ds = repdis[0] + tek_getnum_s7(&s7ptr) + 1; + if (cp == 0) + cp = tek_getnum_s7(&s7ptr) + 16; + cp++; + if (i > 0) { + if (i > 1) { + if (i > 2) + repdis[3] = repdis[2]; + repdis[2] = repdis[1]; + } + repdis[1] = repdis[0]; + repdis[0] = ds; + } + if (q + ds < q0) + goto err; + if (q + cp > q1) + cp = q1 - q; + do { + *q = *(q + ds); + q++; + } while (--cp); + } while (--j); + } while (q < q1); + } + return 0; +err: + return 1; +} + +static int tek_decode2(int siz, UCHAR *p, UCHAR *q) +{ + UCHAR *p1 = p + siz; + int dsiz, hed, bsiz, st = 0; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (dsiz > bsiz || (hed & 0x21) != 0x01) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + st = tek_lzrestore_stk2(p1 - p, p, dsiz, q); + } + return st; +} + +static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int pb, int lp, int flags); + +static int tek_lzrestore_tek5(int srcsiz, UCHAR *src, int outsiz, UCHAR *outbuf) +{ + int wrksiz, lc, lp, pb, flags, *work, prop0, fl; + + if ((fl = (prop0 = *src) & 0x0f) == 0x01) /* 0001 */ + flags |= -1; + else if (fl == 0x05) + flags = -2; + else if (fl == 0x09) + flags &= 0; + else + return 1; + src++; + prop0 >>= 4; + if (prop0 == 0) + prop0 = *src++; + else { + static UCHAR prop0_table[] = { 0x5d, 0x00 }, prop1_table[] = { 0x00 }; + if (flags == -1) { + if (prop0 >= 3) + return 1; + prop0 = prop0_table[prop0 - 1]; + } else { + if (prop0 >= 2) + return 1; + prop0 = prop1_table[prop0 - 1]; + } + } + lp = prop0 / (9 * 5); + prop0 %= 9 * 5; + pb = prop0 / 9; + lc = prop0 % 9; + if (flags == 0) /* tek5:z2 */ + flags = *src++; + if (flags == -1) { /* stk5 */ + wrksiz = lp; + lp = pb; + pb = wrksiz; + } + wrksiz = 0x180 * sizeof (UINT32) + (0x840 + (0x300 << (lc + lp))) * sizeof (tek_TPRB); + work = malloc(wrksiz); + if (work == NULL) + return -1; + flags = tek_decmain5(work, src, outsiz, outbuf, lc, pb, lp, flags); + free(work); + return flags; +} + +struct tek_STR_BITMODEL { + UCHAR t, m, s, dmy; + UINT32 prb0, prb1, tmsk, ntm, lt, lt0, dmy4; +}; + +struct tek_STR_PRB { + struct tek_STR_PRB_PB { + struct tek_STR_PRB_PBST { + tek_TPRB mch, rep0l1; + } st[12]; + tek_TPRB lenlow[2][8], lenmid[2][8]; + } pb[16]; + struct tek_STR_PRB_ST { + tek_TPRB rep, repg0, repg1, repg2; + } st[12]; + tek_TPRB lensel[2][2], lenhigh[2][256], pslot[4][64], algn[64]; + tek_TPRB spdis[2][2+4+8+16+32], lenext[2+4+8+16+32]; + tek_TPRB repg3, fchgprm[2 * 32], tbmt[16], tbmm[16], fchglt; + tek_TPRB lit[1]; +}; + +struct tek_STR_RNGDEC { + UCHAR *p; + UINT32 range, code, rmsk; + jmp_buf errjmp; + struct tek_STR_BITMODEL bm[32], *ptbm[16]; + struct tek_STR_PRB probs; +}; + +static void tek_setbm5(struct tek_STR_BITMODEL *bm, int t, int m) +{ + bm->t = t; + bm->m = m; + bm->prb1 = -1 << (m + t); + bm->prb0 = ~bm->prb1; + bm->prb1 |= 1 << t; + bm->tmsk = (-1 << t) & 0xffff; + bm->prb0 &= bm->tmsk; + bm->prb1 &= bm->tmsk; + bm->ntm = ~bm->tmsk; + return; +} + +static int tek_rdget0(struct tek_STR_RNGDEC *rd, int n, int i) +{ + do { + while (rd->range < (UINT32) (1 << 24)) { + rd->range <<= 8; + rd->code = rd->code << 8 | *rd->p++; + } + rd->range >>= 1; + i += i; + if (rd->code >= rd->range) { + rd->code -= rd->range; + i |= 1; + } + } while (--n); + return ~i; +} + +static int tek_rdget1(struct tek_STR_RNGDEC *rd, tek_TPRB *prob0, int n, int j, struct tek_STR_BITMODEL *bm) +{ + UINT32 p, i, *prob, nm = n >> 4; + n &= 0x0f; + prob0 -= j; + do { + p = *(prob = prob0 + j); + if (bm->lt > 0) { + if (--bm->lt == 0) { + if (tek_rdget1(rd, &rd->probs.fchglt, 0x71, 0, &rd->bm[3]) == 0) { +err: + longjmp(rd->errjmp, 1); + } + i = bm - rd->bm; + if ((bm->s = tek_rdget1(rd, &rd->probs.fchgprm[i * 2 + bm->s], 0x71, 0, &rd->bm[1])) == 0) { + i = tek_rdget1(rd, rd->probs.tbmt, 0x74, 1, &rd->bm[2]) & 15; + if (i == 15) + goto err; + tek_setbm5(bm, i, ((tek_rdget1(rd, rd->probs.tbmm, 0x74, 1, &rd->bm[2]) - 1) & 15) + 1); + } + bm->lt = bm->lt0; + } + if (p < bm->prb0) { + p = bm->prb0; + goto fixprob; + } + if (p > bm->prb1) { + p = bm->prb1; + goto fixprob; + } + if (p & bm->ntm) { + p &= bm->tmsk; + fixprob: + *prob = p; + } + } + + while (rd->range < (UINT32) (1 << 24)) { + rd->range <<= 8; + rd->code = rd->code << 8 | *rd->p++; + } + j += j; + i = ((unsigned long long) (rd->range & rd->rmsk) * p) >> 16; + if (rd->code < i) { + j |= 1; + rd->range = i; + *prob += ((0x10000 - p) >> bm->m) & bm->tmsk; + } else { + rd->range -= i; + rd->code -= i; + *prob -= (p >> bm->m) & bm->tmsk; + } + --n; + if ((n & nm) == 0) + bm++; + } while (n); + return j; +} + +static UINT32 tek_revbit(UINT32 data, int len) +{ + UINT32 rev = 0; + do { + rev += rev + (data & 1); + data >>= 1; + } while (--len); + return rev; +} + +static int tek_getlen5(struct tek_STR_RNGDEC *rd, int m, int s_pos, int stk) +{ + int i; + if (tek_rdget1(rd, &rd->probs.lensel[m][0], 0x71, 0, rd->ptbm[3]) ^ stk) /* low */ + i = tek_rdget1(rd, rd->probs.pb[s_pos].lenlow[m], 0x73, 1, rd->ptbm[4]) & 7; + else if (tek_rdget1(rd, &rd->probs.lensel[m][1], 0x71, 0, rd->ptbm[3]) ^ stk) /* mid */ + i = tek_rdget1(rd, rd->probs.pb[s_pos].lenmid[m], 0x73, 1, rd->ptbm[5]); + else { + /* high */ + i = tek_rdget1(rd, rd->probs.lenhigh[m], 0x78, 1, rd->ptbm[6]) - (256 + 256 - 8); + if (i > 0) { + if (i < 6 && stk == 0) + i = tek_rdget1(rd, &rd->probs.lenext[(1 << i) - 2], i | 0x70, 1, rd->ptbm[7]) - 1; + else + i = tek_rdget0(rd, i, ~1) - 1; + i = tek_rdget0(rd, i, ~1) - 1; + } + i += 256 - 8 + 16; + } + return i; +} + +static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int pb, int lp, int flags) +{ + static int state_table[] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 }; + int i, j, k, pmch, rep[4], s, pos, m_pos = (1 << pb) - 1, m_lp = (1 << lp) - 1; + int stk = (flags == -1), lcr = 8 - lc, s_pos, lit0cntmsk = 0x78; + UINT32 *lit1; + struct tek_STR_RNGDEC *rd = (struct tek_STR_RNGDEC *) work; + struct tek_STR_PRB *prb = &rd->probs; + + rd->p = &src[4]; + rd->range |= -1; + rd->code = src[0] << 24 | src[1] << 16 | src[2] << 8 | src[3]; + for (i = 0; i < 4; i++) + rep[i] = ~i; + if (setjmp(rd->errjmp)) + goto err; + for (i = sizeof (struct tek_STR_PRB) / sizeof (tek_TPRB) + (0x300 << (lc + lp)) - 2; i >= 0; i--) + ((tek_TPRB *) prb)[i] = 1 << 15; + for (i = 0; i < 32; i++) { + rd->bm[i].lt = (i >= 4); + rd->bm[i].lt0 = (i < 24) ? 16 * 1024 : 8 * 1024; + rd->bm[i].s &= 0; + rd->bm[i].t = rd->bm[i].m = 5; + } + lit1 = prb->lit + ((256 << (lc + lp)) - 2); + if (stk) { + rd->rmsk = -1 << 11; + for (i = 0; i < 32; i++) + rd->bm[i].lt = 0; + for (i = 0; i < 14; i++) + rd->ptbm[i] = &rd->bm[0]; + } else { + UCHAR pt[14]; + static UCHAR pt1[14] = { + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 18, 18, 18, 8 + }; + static UCHAR pt2[14] = { + 8, 8, 10, 11, 12, 12, 14, 15, + 16, 16, 18, 18, 20, 21 + }; + /* + 0- 7:mch, mch, lit1, lensel, lenlow, lenmid, lenhigh, lenext + 8-15:pslot, pslot, sdis, sdis, align, rep-repg2 + */ + rd->rmsk |= -1; + rd->bm[1].t = 5; rd->bm[1].m = 3; /* for fchgprm */ + rd->bm[2].t = 9; rd->bm[2].m = 2; /* for tbmt, tbmm */ + if (flags & 0x40) { /* lt-flag */ + rd->bm[3].t = 0; rd->bm[3].m = 1; + prb->fchglt = 0xffff; + } + rd->bm[22].t = 0; rd->bm[22].m = 1; + prb->repg3 = 0xffff; + if (flags == -2) { /* z1 */ + rd->bm[22].lt = 0; + for (i = 0; i < 14; i++) + pt[i] = pt1[i]; + } else { + for (i = 0; i < 14; i++) + pt[i] = pt2[i]; + lit0cntmsk = (7 >> (flags & 3)) << 4 | 8; + pt[ 1] = 8 + ((flags & 0x04) != 0); /* mch */ + pt[ 5] = 12 + ((flags & 0x08) != 0); /* llm */ + pt[ 9] = 16 + ((flags & 0x10) != 0); /* pst */ + pt[11] = 18 + ((flags & 0x20) != 0); /* sds */ + } + for (i = 0; i < 14; i++) + rd->ptbm[i] = &rd->bm[pt[i]]; + } + for (i = 0; i < 32; i++) + tek_setbm5(&rd->bm[i], rd->bm[i].t, rd->bm[i].m); + + if ((tek_rdget1(rd, &prb->pb[0].st[0].mch, 0x71, 0, rd->ptbm[0]) ^ stk) == 0) + goto err; + *q++ = tek_rdget1(rd, prb->lit, lit0cntmsk, 1, &rd->bm[24]) & 0xff; + pmch &= 0; s &= 0; pos = 1; + while (pos < osiz) { + s_pos = pos & m_pos; + if (tek_rdget1(rd, &prb->pb[s_pos].st[s].mch, 0x71, 0, rd->ptbm[s > 0]) ^ stk) { + i = (q[-1] >> lcr | (pos & m_lp) << lc) << 8; + s = state_table[s]; + if (pmch == 0) + *q = tek_rdget1(rd, &prb->lit[i], lit0cntmsk, 1, &rd->bm[24]) & 0xff; + else { + struct tek_STR_BITMODEL *bm = &rd->bm[24]; + j = 1; /* lit1‚͍ŏ‰‚©‚ç2‚ðŒ¸‚¶‚Ä‚ ‚é */ + k = 8; + pmch = q[rep[0]]; + do { + j += j + tek_rdget1(rd, &lit1[(i + j) << 1 | pmch >> 7], 0x71, 0, rd->ptbm[2]); + k--; + if ((k & (lit0cntmsk >> 4)) == 0) + bm++; + if ((((pmch >> 7) ^ j) & 1) != 0 && k != 0) { + j = tek_rdget1(rd, &prb->lit[i + j - 1], k | (lit0cntmsk & 0x70), j, bm); + break; + } + pmch <<= 1; + } while (k); + *q = j & 0xff; + pmch &= 0; + } + pos++; + q++; + } else { /* lz */ + pmch |= 1; + if (tek_rdget1(rd, &prb->st[s].rep, 0x71, 0, rd->ptbm[13]) ^ stk) { /* len/dis */ + rep[3] = rep[2]; + rep[2] = rep[1]; + rep[1] = rep[0]; + j = i = tek_getlen5(rd, 0, s_pos, stk); + s = s < 7 ? 7 : 10; + if (j >= 4) + j = 3; + rep[0] = j = tek_rdget1(rd, prb->pslot[j], 0x76, 1, rd->ptbm[8 + (j == 3)]) & 0x3f; + if (j >= 4) { + k = (j >> 1) - 1; /* k = [1, 30] */ + rep[0] = (2 | (j & 1)) << k; + if (j < 14) /* k < 6 */ + rep[0] |= tek_revbit(tek_rdget1(rd, &prb->spdis[j & 1][(1 << k) - 2], k | 0x70, 1, rd->ptbm[10 + (k >= 4)]), k); + else { + if (stk == 0) { + if (k -= 6) + rep[0] |= tek_rdget0(rd, k, ~0) << 6; + rep[0] |= tek_revbit(tek_rdget1(rd, prb->algn, 0x76, 1, rd->ptbm[12]), 6); + } else { + rep[0] |= tek_rdget0(rd, k - 4, ~0) << 4; + rep[0] |= tek_revbit(tek_rdget1(rd, prb->algn, 0x74, 1, rd->ptbm[12]), 4); + } + } + } + rep[0] = ~rep[0]; + } else { /* repeat-dis */ + if (tek_rdget1(rd, &prb->st[s].repg0, 0x71, 0, rd->ptbm[13]) ^ stk) { /* rep0 */ + i |= -1; + if (tek_rdget1(rd, &prb->pb[s_pos].st[s].rep0l1, 0x71, 0, rd->ptbm[13]) == 0) { + s = s < 7 ? 9 : 11; + goto skip; + } + } else { + if (tek_rdget1(rd, &prb->st[s].repg1, 0x71, 0, rd->ptbm[13]) ^ stk) /* rep1 */ + i = rep[1]; + else { + if (tek_rdget1(rd, &prb->st[s].repg2, 0x71, 0, rd->ptbm[13]) ^ stk) /* rep2 */ + i = rep[2]; + else { + if (stk == 0) { + if (tek_rdget1(rd, &prb->repg3, 0x71, 0, &rd->bm[22]) == 0) + goto err; + } + i = rep[3]; /* rep3 */ + rep[3] = rep[2]; + } + rep[2] = rep[1]; + } + rep[1] = rep[0]; + rep[0] = i; + } + i = tek_getlen5(rd, 1, s_pos, stk); + s = s < 7 ? 8 : 11; + } +skip: + i += 2; + if (pos + rep[0] < 0) + goto err; + if (pos + i > osiz) + i = osiz - pos; + pos += i; + do { + *q = q[rep[0]]; + q++; + } while (--i); + } + } + return 0; +err: + return 1; +} + +int tek_decode5(int siz, UCHAR *p, UCHAR *q) +{ + UCHAR *p1 = p + siz; + int dsiz, hed, bsiz, st = 0; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + if ((hed & 1) == 0) + st = tek_lzrestore_tek5(p1 - p + 1, p - 1, dsiz, q); + else { + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (hed & 0x20) + return 1; + if (bsiz == 256) + st = tek_lzrestore_tek5(p1 - p, p, dsiz, q); + else { + if (dsiz > bsiz) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + st = tek_lzrestore_tek5(p1 - p, p, dsiz, q); + } + } + } + return st; +} diff --git a/30_day/tek/tek.c b/30_day/tek/tek.c new file mode 100644 index 0000000..4062dcc --- /dev/null +++ b/30_day/tek/tek.c @@ -0,0 +1,646 @@ +#include "bootpack.h" +#include +#include +#define NULL 0 + +typedef unsigned char UCHAR; +typedef unsigned int UINT32; +typedef UINT32 tek_TPRB; + +static int tek_decode1(int siz, UCHAR *p, UCHAR *q); +static int tek_decode2(int siz, UCHAR *p, UCHAR *q); +static int tek_decode5(int siz, UCHAR *p, UCHAR *q); + +static unsigned int tek_getnum_s7s(UCHAR **pp) +{ + unsigned int s = 0; + UCHAR *p = *pp; + do { + s = s << 7 | *p++; + } while ((s & 1) == 0); + s >>= 1; + *pp = p; + return s; +} + +int tek_getsize(unsigned char *p) +{ + static char header[15] = { + 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x41, 0x53, 0x4b, 0x43, 0x4d, 0x50 + }; + int size = -1; + if (memcmp(p + 1, header, 15) == 0 && (*p == 0x83 || *p == 0x85 || *p == 0x89)) { + p += 16; + size = tek_getnum_s7s(&p); + } + return size; +} /* (注)memcmp和strncmp差不多,这个函数忽略字符串中的0并一直比较到指定的15个字符为止*/ + +int tek_decomp(unsigned char *p, char *q, int size) +{ + int err = -1; + if (*p == 0x83) { + err = tek_decode1(size, p, q); + } else if (*p == 0x85) { + err = tek_decode2(size, p, q); + } else if (*p == 0x89) { + err = tek_decode5(size, p, q); + } + if (err != 0) { + return -1; /*失败*/ + } + return 0; /*成功*/ +} + +static int tek_lzrestore_stk1(int srcsiz, UCHAR *src, int outsiz, UCHAR *q) +{ + int by, lz, cp, ds; + UCHAR *q1 = q + outsiz, *s7ptr = src, *q0 = q; + do { + if ((by = (lz = *s7ptr++) & 0x0f) == 0) + by = tek_getnum_s7s(&s7ptr); + if ((lz >>= 4) == 0) + lz = tek_getnum_s7s(&s7ptr); + do { + *q++ = *s7ptr++; + } while (--by); + if (q >= q1) + break; + do { + ds = (cp = *s7ptr++) & 0x0f; + if ((ds & 1) == 0) { + do { + ds = ds << 7 | *s7ptr++; + } while ((ds & 1) == 0); + } + ds = ~(ds >> 1); + if ((cp >>= 4) == 0) { + do { + cp = cp << 7 | *s7ptr++; + } while ((cp & 1) == 0); + cp >>= 1; + } + cp++; + if (q + ds < q0) + goto err; + if (q + cp > q1) + cp = q1 - q; + do { + *q = *(q + ds); + q++; + } while (--cp); + } while (--lz); + } while (q < q1); + return 0; +err: + return 1; +} + +static int tek_decode1(int siz, UCHAR *p, UCHAR *q) +{ + int dsiz, hed, bsiz; + UCHAR *p1 = p + siz; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (dsiz > bsiz || (hed & 0x21) != 0x01) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + if (tek_getnum_s7s(&p) != 0) + return 1; + return tek_lzrestore_stk1(p1 - p, p, dsiz, q); + } + return 0; +} + +static unsigned int tek_getnum_s7(UCHAR **pp) +{ + unsigned int s = 0, b = 0, a = 1; + UCHAR *p = *pp; + for (;;) { + s = s << 7 | *p++; + if (s & 1) + break; + a <<= 7; + b += a; + } + s >>= 1; + *pp = p; + return s + b; +} + +static int tek_lzrestore_stk2(int srcsiz, UCHAR *src, int outsiz, UCHAR *q) +{ + int cp, ds, repdis[4], i, j; + UCHAR *q1 = q + outsiz, *s7ptr = src, *q0 = q, bylz, cbylz; + for (j = 0; j < 4; j++) + repdis[j] = -1 - j; + bylz = cbylz = 0; + if (outsiz) { + if (tek_getnum_s7s(&s7ptr)) + return 1; + do { + j = 0; + do { + j++; + if (j >= 17) { + j += tek_getnum_s7s(&s7ptr); + break; + } + if (cbylz == 0) { + cbylz = 8; + bylz = *s7ptr++; + } + cbylz--; + i = bylz & 1; + bylz >>= 1; + } while (i == 0); + do { + *q++ = *s7ptr++; + } while (--j); + if (q >= q1) + break; + + j = 0; + do { + j++; + if (j >= 17) { + j += tek_getnum_s7s(&s7ptr); + break; + } + if (cbylz == 0) { + cbylz = 8; + bylz = *s7ptr++; + } + cbylz--; + i = bylz & 1; + bylz >>= 1; + } while (i == 0); + do { + i = *s7ptr++; + cp = i >> 4; + i &= 0x0f; + if ((i & 1) == 0) + i |= (tek_getnum_s7(&s7ptr) + 1) << 4; + i >>= 1; + ds = ~(i - 6); + if (i < 4) + ds = repdis[i]; + if (i == 4) + ds = repdis[0] - tek_getnum_s7(&s7ptr) - 1; + if (i == 5) + ds = repdis[0] + tek_getnum_s7(&s7ptr) + 1; + if (cp == 0) + cp = tek_getnum_s7(&s7ptr) + 16; + cp++; + if (i > 0) { + if (i > 1) { + if (i > 2) + repdis[3] = repdis[2]; + repdis[2] = repdis[1]; + } + repdis[1] = repdis[0]; + repdis[0] = ds; + } + if (q + ds < q0) + goto err; + if (q + cp > q1) + cp = q1 - q; + do { + *q = *(q + ds); + q++; + } while (--cp); + } while (--j); + } while (q < q1); + } + return 0; +err: + return 1; +} + +static int tek_decode2(int siz, UCHAR *p, UCHAR *q) +{ + UCHAR *p1 = p + siz; + int dsiz, hed, bsiz, st = 0; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (dsiz > bsiz || (hed & 0x21) != 0x01) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + st = tek_lzrestore_stk2(p1 - p, p, dsiz, q); + } + return st; +} + +static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int pb, int lp, int flags); + +static int tek_lzrestore_tek5(int srcsiz, UCHAR *src, int outsiz, UCHAR *outbuf) +{ + int wrksiz, lc, lp, pb, flags, *work, prop0, fl; + + if ((fl = (prop0 = *src) & 0x0f) == 0x01) /* 0001 */ + flags |= -1; + else if (fl == 0x05) + flags = -2; + else if (fl == 0x09) + flags &= 0; + else + return 1; + src++; + prop0 >>= 4; + if (prop0 == 0) + prop0 = *src++; + else { + static UCHAR prop0_table[] = { 0x5d, 0x00 }, prop1_table[] = { 0x00 }; + if (flags == -1) { + if (prop0 >= 3) + return 1; + prop0 = prop0_table[prop0 - 1]; + } else { + if (prop0 >= 2) + return 1; + prop0 = prop1_table[prop0 - 1]; + } + } + lp = prop0 / (9 * 5); + prop0 %= 9 * 5; + pb = prop0 / 9; + lc = prop0 % 9; + if (flags == 0) /* tek5:z2 */ + flags = *src++; + if (flags == -1) { /* stk5 */ + wrksiz = lp; + lp = pb; + pb = wrksiz; + } + wrksiz = 0x180 * sizeof (UINT32) + (0x840 + (0x300 << (lc + lp))) * sizeof (tek_TPRB); /* Å’á15KB, lc+lp=3‚È‚çA36KB */ + work = (int *) memman_alloc_4k((struct MEMMAN *) MEMMAN_ADDR, wrksiz); + if (work == NULL) + return -1; + flags = tek_decmain5(work, src, outsiz, outbuf, lc, pb, lp, flags); + memman_free_4k((struct MEMMAN *) MEMMAN_ADDR, (int) work, wrksiz); + return flags; +} + +struct tek_STR_BITMODEL { + UCHAR t, m, s, dmy; + UINT32 prb0, prb1, tmsk, ntm, lt, lt0, dmy4; +}; + +struct tek_STR_PRB { + struct tek_STR_PRB_PB { + struct tek_STR_PRB_PBST { + tek_TPRB mch, rep0l1; + } st[12]; + tek_TPRB lenlow[2][8], lenmid[2][8]; + } pb[16]; + struct tek_STR_PRB_ST { + tek_TPRB rep, repg0, repg1, repg2; + } st[12]; + tek_TPRB lensel[2][2], lenhigh[2][256], pslot[4][64], algn[64]; + tek_TPRB spdis[2][2+4+8+16+32], lenext[2+4+8+16+32]; + tek_TPRB repg3, fchgprm[2 * 32], tbmt[16], tbmm[16], fchglt; + tek_TPRB lit[1]; +}; + +struct tek_STR_RNGDEC { + UCHAR *p; + UINT32 range, code, rmsk; + jmp_buf errjmp; + struct tek_STR_BITMODEL bm[32], *ptbm[16]; + struct tek_STR_PRB probs; +}; + +static void tek_setbm5(struct tek_STR_BITMODEL *bm, int t, int m) +{ + bm->t = t; + bm->m = m; + bm->prb1 = -1 << (m + t); + bm->prb0 = ~bm->prb1; + bm->prb1 |= 1 << t; + bm->tmsk = (-1 << t) & 0xffff; + bm->prb0 &= bm->tmsk; + bm->prb1 &= bm->tmsk; + bm->ntm = ~bm->tmsk; + return; +} + +static int tek_rdget0(struct tek_STR_RNGDEC *rd, int n, int i) +{ + do { + while (rd->range < (UINT32) (1 << 24)) { + rd->range <<= 8; + rd->code = rd->code << 8 | *rd->p++; + } + rd->range >>= 1; + i += i; + if (rd->code >= rd->range) { + rd->code -= rd->range; + i |= 1; + } + } while (--n); + return ~i; +} + +static int tek_rdget1(struct tek_STR_RNGDEC *rd, tek_TPRB *prob0, int n, int j, struct tek_STR_BITMODEL *bm) +{ + UINT32 p, i, *prob, nm = n >> 4; + n &= 0x0f; + prob0 -= j; + do { + p = *(prob = prob0 + j); + if (bm->lt > 0) { + if (--bm->lt == 0) { + if (tek_rdget1(rd, &rd->probs.fchglt, 0x71, 0, &rd->bm[3]) == 0) { +err: + longjmp(rd->errjmp, 1); + } + i = bm - rd->bm; + if ((bm->s = tek_rdget1(rd, &rd->probs.fchgprm[i * 2 + bm->s], 0x71, 0, &rd->bm[1])) == 0) { + i = tek_rdget1(rd, rd->probs.tbmt, 0x74, 1, &rd->bm[2]) & 15; + if (i == 15) + goto err; + tek_setbm5(bm, i, ((tek_rdget1(rd, rd->probs.tbmm, 0x74, 1, &rd->bm[2]) - 1) & 15) + 1); + } + bm->lt = bm->lt0; + } + if (p < bm->prb0) { + p = bm->prb0; + goto fixprob; + } + if (p > bm->prb1) { + p = bm->prb1; + goto fixprob; + } + if (p & bm->ntm) { + p &= bm->tmsk; + fixprob: + *prob = p; + } + } + + while (rd->range < (UINT32) (1 << 24)) { + rd->range <<= 8; + rd->code = rd->code << 8 | *rd->p++; + } + j += j; + i = ((unsigned long long) (rd->range & rd->rmsk) * p) >> 16; + if (rd->code < i) { + j |= 1; + rd->range = i; + *prob += ((0x10000 - p) >> bm->m) & bm->tmsk; + } else { + rd->range -= i; + rd->code -= i; + *prob -= (p >> bm->m) & bm->tmsk; + } + --n; + if ((n & nm) == 0) + bm++; + } while (n); + return j; +} + +static UINT32 tek_revbit(UINT32 data, int len) +{ + UINT32 rev = 0; + do { + rev += rev + (data & 1); + data >>= 1; + } while (--len); + return rev; +} + +static int tek_getlen5(struct tek_STR_RNGDEC *rd, int m, int s_pos, int stk) +{ + int i; + if (tek_rdget1(rd, &rd->probs.lensel[m][0], 0x71, 0, rd->ptbm[3]) ^ stk) /* low */ + i = tek_rdget1(rd, rd->probs.pb[s_pos].lenlow[m], 0x73, 1, rd->ptbm[4]) & 7; + else if (tek_rdget1(rd, &rd->probs.lensel[m][1], 0x71, 0, rd->ptbm[3]) ^ stk) /* mid */ + i = tek_rdget1(rd, rd->probs.pb[s_pos].lenmid[m], 0x73, 1, rd->ptbm[5]); + else { + /* high */ + i = tek_rdget1(rd, rd->probs.lenhigh[m], 0x78, 1, rd->ptbm[6]) - (256 + 256 - 8); + if (i > 0) { + if (i < 6 && stk == 0) + i = tek_rdget1(rd, &rd->probs.lenext[(1 << i) - 2], i | 0x70, 1, rd->ptbm[7]) - 1; + else + i = tek_rdget0(rd, i, ~1) - 1; + i = tek_rdget0(rd, i, ~1) - 1; + } + i += 256 - 8 + 16; + } + return i; +} + +static int tek_decmain5(int *work, UCHAR *src, int osiz, UCHAR *q, int lc, int pb, int lp, int flags) +{ + static int state_table[] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 }; + int i, j, k, pmch, rep[4], s, pos, m_pos = (1 << pb) - 1, m_lp = (1 << lp) - 1; + int stk = (flags == -1), lcr = 8 - lc, s_pos, lit0cntmsk = 0x78; + UINT32 *lit1; + struct tek_STR_RNGDEC *rd = (struct tek_STR_RNGDEC *) work; + struct tek_STR_PRB *prb = &rd->probs; + + rd->p = &src[4]; + rd->range |= -1; + rd->code = src[0] << 24 | src[1] << 16 | src[2] << 8 | src[3]; + for (i = 0; i < 4; i++) + rep[i] = ~i; + if (setjmp(rd->errjmp)) + goto err; + for (i = sizeof (struct tek_STR_PRB) / sizeof (tek_TPRB) + (0x300 << (lc + lp)) - 2; i >= 0; i--) + ((tek_TPRB *) prb)[i] = 1 << 15; + for (i = 0; i < 32; i++) { + rd->bm[i].lt = (i >= 4); + rd->bm[i].lt0 = (i < 24) ? 16 * 1024 : 8 * 1024; + rd->bm[i].s &= 0; + rd->bm[i].t = rd->bm[i].m = 5; + } + lit1 = prb->lit + ((256 << (lc + lp)) - 2); + if (stk) { + rd->rmsk = -1 << 11; + for (i = 0; i < 32; i++) + rd->bm[i].lt = 0; + for (i = 0; i < 14; i++) + rd->ptbm[i] = &rd->bm[0]; + } else { + UCHAR pt[14]; + static UCHAR pt1[14] = { + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 18, 18, 18, 8 + }; + static UCHAR pt2[14] = { + 8, 8, 10, 11, 12, 12, 14, 15, + 16, 16, 18, 18, 20, 21 + }; + /* + 0- 7:mch, mch, lit1, lensel, lenlow, lenmid, lenhigh, lenext + 8-15:pslot, pslot, sdis, sdis, align, rep-repg2 + */ + rd->rmsk |= -1; + rd->bm[1].t = 5; rd->bm[1].m = 3; /* for fchgprm */ + rd->bm[2].t = 9; rd->bm[2].m = 2; /* for tbmt, tbmm */ + if (flags & 0x40) { /* lt-flag */ + rd->bm[3].t = 0; rd->bm[3].m = 1; + prb->fchglt = 0xffff; + } + rd->bm[22].t = 0; rd->bm[22].m = 1; + prb->repg3 = 0xffff; + if (flags == -2) { /* z1 */ + rd->bm[22].lt = 0; + for (i = 0; i < 14; i++) + pt[i] = pt1[i]; + } else { + for (i = 0; i < 14; i++) + pt[i] = pt2[i]; + lit0cntmsk = (7 >> (flags & 3)) << 4 | 8; + pt[ 1] = 8 + ((flags & 0x04) != 0); /* mch */ + pt[ 5] = 12 + ((flags & 0x08) != 0); /* llm */ + pt[ 9] = 16 + ((flags & 0x10) != 0); /* pst */ + pt[11] = 18 + ((flags & 0x20) != 0); /* sds */ + } + for (i = 0; i < 14; i++) + rd->ptbm[i] = &rd->bm[pt[i]]; + } + for (i = 0; i < 32; i++) + tek_setbm5(&rd->bm[i], rd->bm[i].t, rd->bm[i].m); + + if ((tek_rdget1(rd, &prb->pb[0].st[0].mch, 0x71, 0, rd->ptbm[0]) ^ stk) == 0) + goto err; + *q++ = tek_rdget1(rd, prb->lit, lit0cntmsk, 1, &rd->bm[24]) & 0xff; + pmch &= 0; s &= 0; pos = 1; + while (pos < osiz) { + s_pos = pos & m_pos; + if (tek_rdget1(rd, &prb->pb[s_pos].st[s].mch, 0x71, 0, rd->ptbm[s > 0]) ^ stk) { + i = (q[-1] >> lcr | (pos & m_lp) << lc) << 8; + s = state_table[s]; + if (pmch == 0) + *q = tek_rdget1(rd, &prb->lit[i], lit0cntmsk, 1, &rd->bm[24]) & 0xff; + else { + struct tek_STR_BITMODEL *bm = &rd->bm[24]; + j = 1; + k = 8; + pmch = q[rep[0]]; + do { + j += j + tek_rdget1(rd, &lit1[(i + j) << 1 | pmch >> 7], 0x71, 0, rd->ptbm[2]); + k--; + if ((k & (lit0cntmsk >> 4)) == 0) + bm++; + if ((((pmch >> 7) ^ j) & 1) != 0 && k != 0) { + j = tek_rdget1(rd, &prb->lit[i + j - 1], k | (lit0cntmsk & 0x70), j, bm); + break; + } + pmch <<= 1; + } while (k); + *q = j & 0xff; + pmch &= 0; + } + pos++; + q++; + } else { /* lz */ + pmch |= 1; + if (tek_rdget1(rd, &prb->st[s].rep, 0x71, 0, rd->ptbm[13]) ^ stk) { /* len/dis */ + rep[3] = rep[2]; + rep[2] = rep[1]; + rep[1] = rep[0]; + j = i = tek_getlen5(rd, 0, s_pos, stk); + s = s < 7 ? 7 : 10; + if (j >= 4) + j = 3; + rep[0] = j = tek_rdget1(rd, prb->pslot[j], 0x76, 1, rd->ptbm[8 + (j == 3)]) & 0x3f; + if (j >= 4) { + k = (j >> 1) - 1; /* k = [1, 30] */ + rep[0] = (2 | (j & 1)) << k; + if (j < 14) /* k < 6 */ + rep[0] |= tek_revbit(tek_rdget1(rd, &prb->spdis[j & 1][(1 << k) - 2], k | 0x70, 1, rd->ptbm[10 + (k >= 4)]), k); + else { + if (stk == 0) { + if (k -= 6) + rep[0] |= tek_rdget0(rd, k, ~0) << 6; + rep[0] |= tek_revbit(tek_rdget1(rd, prb->algn, 0x76, 1, rd->ptbm[12]), 6); + } else { + rep[0] |= tek_rdget0(rd, k - 4, ~0) << 4; + rep[0] |= tek_revbit(tek_rdget1(rd, prb->algn, 0x74, 1, rd->ptbm[12]), 4); + } + } + } + rep[0] = ~rep[0]; + } else { /* repeat-dis */ + if (tek_rdget1(rd, &prb->st[s].repg0, 0x71, 0, rd->ptbm[13]) ^ stk) { /* rep0 */ + i |= -1; + if (tek_rdget1(rd, &prb->pb[s_pos].st[s].rep0l1, 0x71, 0, rd->ptbm[13]) == 0) { + s = s < 7 ? 9 : 11; + goto skip; + } + } else { + if (tek_rdget1(rd, &prb->st[s].repg1, 0x71, 0, rd->ptbm[13]) ^ stk) /* rep1 */ + i = rep[1]; + else { + if (tek_rdget1(rd, &prb->st[s].repg2, 0x71, 0, rd->ptbm[13]) ^ stk) /* rep2 */ + i = rep[2]; + else { + if (stk == 0) { + if (tek_rdget1(rd, &prb->repg3, 0x71, 0, &rd->bm[22]) == 0) + goto err; + } + i = rep[3]; /* rep3 */ + rep[3] = rep[2]; + } + rep[2] = rep[1]; + } + rep[1] = rep[0]; + rep[0] = i; + } + i = tek_getlen5(rd, 1, s_pos, stk); + s = s < 7 ? 8 : 11; + } +skip: + i += 2; + if (pos + rep[0] < 0) + goto err; + if (pos + i > osiz) + i = osiz - pos; + pos += i; + do { + *q = q[rep[0]]; + q++; + } while (--i); + } + } + return 0; +err: + return 1; +} + +static int tek_decode5(int siz, UCHAR *p, UCHAR *q) +{ + UCHAR *p1 = p + siz; + int dsiz, hed, bsiz, st = 0; + p += 16; + if ((dsiz = tek_getnum_s7s(&p)) > 0) { + hed = tek_getnum_s7s(&p); + if ((hed & 1) == 0) + st = tek_lzrestore_tek5(p1 - p + 1, p - 1, dsiz, q); + else { + bsiz = 1 << (((hed >> 1) & 0x0f) + 8); + if (hed & 0x20) + return 1; + if (bsiz == 256) + st = tek_lzrestore_tek5(p1 - p, p, dsiz, q); + else { + if (dsiz > bsiz) + return 1; + if (hed & 0x40) + tek_getnum_s7s(&p); + st = tek_lzrestore_tek5(p1 - p, p, dsiz, q); + } + } + } + return st; +} diff --git a/30_day/type/!cons_9x.bat b/30_day/type/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/type/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/type/!cons_nt.bat b/30_day/type/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/type/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/type/Makefile b/30_day/type/Makefile new file mode 100644 index 0000000..7314b7b --- /dev/null +++ b/30_day/type/Makefile @@ -0,0 +1,5 @@ +APP = type +STACK = 1k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/type/make.bat b/30_day/type/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/type/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/type/type.c b/30_day/type/type.c new file mode 100644 index 0000000..c6fc99f --- /dev/null +++ b/30_day/type/type.c @@ -0,0 +1,23 @@ +#include "apilib.h" + +void HariMain(void) +{ + int fh; + char c, cmdline[30], *p; + + api_cmdline(cmdline, 30); + for (p = cmdline; *p > ' '; p++) { } /*跳过之前的内容,直到遇到空格*/ + for (; *p == ' '; p++) { } /*跳过空格*/ + fh = api_fopen(p); + if (fh != 0) { + for (;;) { + if (api_fread(&c, 1, fh) == 0) { + break; + } + api_putchar(c); + } + } else { + api_putstr0("File not found.\n"); + } + api_end(); +} diff --git a/30_day/walk/!cons_9x.bat b/30_day/walk/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/walk/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/walk/!cons_nt.bat b/30_day/walk/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/walk/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/walk/Makefile b/30_day/walk/Makefile new file mode 100644 index 0000000..641c368 --- /dev/null +++ b/30_day/walk/Makefile @@ -0,0 +1,5 @@ +APP = walk +STACK = 1k +MALLOC = 48k + +include ../app_make.txt diff --git a/30_day/walk/make.bat b/30_day/walk/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/walk/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/walk/walk.c b/30_day/walk/walk.c new file mode 100644 index 0000000..4772f8a --- /dev/null +++ b/30_day/walk/walk.c @@ -0,0 +1,26 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win, i, x, y; + api_initmalloc(); + buf = api_malloc(160 * 100); + win = api_openwin(buf, 160, 100, -1, "walk"); + api_boxfilwin(win, 4, 24, 155, 95, 0);/*黑色*/ + x = 76; + y = 56; + api_putstrwin(win, x, y, 3, 1, "*");/*黄色*/ + for (;;) { + i = api_getkey(1); + api_putstrwin(win, x, y, 0 , 1, "*"); /*用黑色擦除*/ + if (i == '4' && x > 4) { x -= 8; } + if (i == '6' && x < 148) { x += 8; } + if (i == '8' && y > 24) { y -= 8; } + if (i == '2' && y < 80) { y += 8; } + if (i == 0x0a) { break; } /*按回车键结束*/ + api_putstrwin(win, x, y, 3 , 1, "*");/*黄色*/ + } + api_closewin(win); + api_end(); +} diff --git a/30_day/winhelo/!cons_9x.bat b/30_day/winhelo/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/winhelo/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/winhelo/!cons_nt.bat b/30_day/winhelo/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/winhelo/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/winhelo/Makefile b/30_day/winhelo/Makefile new file mode 100644 index 0000000..91d9264 --- /dev/null +++ b/30_day/winhelo/Makefile @@ -0,0 +1,9 @@ +APP = winhelo +STACK = 8k +MALLOC = 0k + +include ../app_make.txt + +$(APP).hrb : $(APP).org Makefile + $(COPY) $(APP).org $(APP).hrb + \ No newline at end of file diff --git a/30_day/winhelo/make.bat b/30_day/winhelo/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/winhelo/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/winhelo/winhelo.c b/30_day/winhelo/winhelo.c new file mode 100644 index 0000000..c36e988 --- /dev/null +++ b/30_day/winhelo/winhelo.c @@ -0,0 +1,15 @@ +#include "apilib.h" + +void HariMain(void) +{ + int win; + char buf[150 * 50]; + + win = api_openwin(buf, 150, 50, -1, "hello"); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/30_day/winhelo2/!cons_9x.bat b/30_day/winhelo2/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/winhelo2/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/winhelo2/!cons_nt.bat b/30_day/winhelo2/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/winhelo2/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/winhelo2/Makefile b/30_day/winhelo2/Makefile new file mode 100644 index 0000000..a1544f5 --- /dev/null +++ b/30_day/winhelo2/Makefile @@ -0,0 +1,5 @@ +APP = winhelo2 +STACK = 8k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/winhelo2/make.bat b/30_day/winhelo2/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/winhelo2/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/winhelo2/winhelo2.c b/30_day/winhelo2/winhelo2.c new file mode 100644 index 0000000..dfc4ce7 --- /dev/null +++ b/30_day/winhelo2/winhelo2.c @@ -0,0 +1,17 @@ +#include "apilib.h" + +void HariMain(void) +{ + int win; + char buf[150 * 50]; + + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 3); /*黄色*/ + api_putstrwin(win, 28, 28, 0 /*黑色*/, 12, "hello, world"); + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} diff --git a/30_day/winhelo3/!cons_9x.bat b/30_day/winhelo3/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/winhelo3/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/winhelo3/!cons_nt.bat b/30_day/winhelo3/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/winhelo3/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/winhelo3/Makefile b/30_day/winhelo3/Makefile new file mode 100644 index 0000000..719b23a --- /dev/null +++ b/30_day/winhelo3/Makefile @@ -0,0 +1,5 @@ +APP = winhelo3 +STACK = 1k +MALLOC = 40k + +include ../app_make.txt diff --git a/30_day/winhelo3/make.bat b/30_day/winhelo3/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/winhelo3/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/winhelo3/winhelo3.c b/30_day/winhelo3/winhelo3.c new file mode 100644 index 0000000..a1529e5 --- /dev/null +++ b/30_day/winhelo3/winhelo3.c @@ -0,0 +1,19 @@ +#include "apilib.h" + +void HariMain(void) +{ + char *buf; + int win; + + api_initmalloc(); + buf = api_malloc(150 * 50); + win = api_openwin(buf, 150, 50, -1, "hello"); + api_boxfilwin(win, 8, 36, 141, 43, 6); /*浅蓝色*/ + api_putstrwin(win, 28, 28, 0 , 12, "hello, world");/*黑色*/ + for (;;) { + if (api_getkey(1) == 0x0a) { + break; /*按下回车键则break; */ + } + } + api_end(); +} From 70b335278d015965e1d75d316cc2f02d33caf22d Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 20 May 2016 10:54:34 +0800 Subject: [PATCH 63/83] bug fix --- 29_day/Makefile | 3 +++ 30_day/Makefile | 3 +++ 2 files changed, 6 insertions(+) diff --git a/29_day/Makefile b/29_day/Makefile index f92b3d5..cfc8f48 100644 --- a/29_day/Makefile +++ b/29_day/Makefile @@ -71,6 +71,7 @@ install : full : $(MAKE) -C haribote $(MAKE) -C apilib + $(MAKE) -C stdlib $(MAKE) -C a $(MAKE) -C hello3 $(MAKE) -C hello4 @@ -121,6 +122,7 @@ src_only : clean_full : $(MAKE) -C haribote clean $(MAKE) -C apilib clean + $(MAKE) -C stdlib clean $(MAKE) -C a clean $(MAKE) -C hello3 clean $(MAKE) -C hello4 clean @@ -150,6 +152,7 @@ clean_full : src_only_full : $(MAKE) -C haribote src_only $(MAKE) -C apilib src_only + $(MAKE) -C stdlib src_only $(MAKE) -C a src_only $(MAKE) -C hello3 src_only $(MAKE) -C hello4 src_only diff --git a/30_day/Makefile b/30_day/Makefile index f92b3d5..cfc8f48 100644 --- a/30_day/Makefile +++ b/30_day/Makefile @@ -71,6 +71,7 @@ install : full : $(MAKE) -C haribote $(MAKE) -C apilib + $(MAKE) -C stdlib $(MAKE) -C a $(MAKE) -C hello3 $(MAKE) -C hello4 @@ -121,6 +122,7 @@ src_only : clean_full : $(MAKE) -C haribote clean $(MAKE) -C apilib clean + $(MAKE) -C stdlib clean $(MAKE) -C a clean $(MAKE) -C hello3 clean $(MAKE) -C hello4 clean @@ -150,6 +152,7 @@ clean_full : src_only_full : $(MAKE) -C haribote src_only $(MAKE) -C apilib src_only + $(MAKE) -C stdlib src_only $(MAKE) -C a src_only $(MAKE) -C hello3 src_only $(MAKE) -C hello4 src_only From 3871740126956606ce99157f300d3f89d7ff00f3 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 20 May 2016 11:01:41 +0800 Subject: [PATCH 64/83] =?UTF-8?q?=E5=91=BD=E4=BB=A4=E8=A1=8C=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 30_day/Makefile | 7 +- 30_day/calc/!cons_9x.bat | 1 + 30_day/calc/!cons_nt.bat | 1 + 30_day/calc/Makefile | 5 ++ 30_day/calc/calc.c | 163 +++++++++++++++++++++++++++++++++++++++ 30_day/calc/make.bat | 1 + 6 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 30_day/calc/!cons_9x.bat create mode 100644 30_day/calc/!cons_nt.bat create mode 100644 30_day/calc/Makefile create mode 100644 30_day/calc/calc.c create mode 100644 30_day/calc/make.bat diff --git a/30_day/Makefile b/30_day/Makefile index cfc8f48..efee1ad 100644 --- a/30_day/Makefile +++ b/30_day/Makefile @@ -22,7 +22,8 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ beepdown/beepdown.hrb color/color.hrb color2/color2.hrb \ sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb \ type/type.hrb iroha/iroha.hrb chklang/chklang.hrb \ - notrec/notrec.hrb bball/bball.hrb invader/invader.hrb + notrec/notrec.hrb bball/bball.hrb invader/invader.hrb \ + calc/calc.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:haribote/ipl20.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ @@ -54,6 +55,7 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ copy from:notrec/notrec.hrb to:@: \ copy from:bball/bball.hrb to:@: \ copy from:invader/invader.hrb to:@: \ + copy from:calc/calc.hrb to:@: \ copy from:nihongo/nihongo.fnt to:@: \ imgout:haribote.img @@ -97,6 +99,7 @@ full : $(MAKE) -C notrec $(MAKE) -C bball $(MAKE) -C invader + $(MAKE) -C calc $(MAKE) haribote.img run_full : @@ -148,6 +151,7 @@ clean_full : $(MAKE) -C notrec clean $(MAKE) -C bball clean $(MAKE) -C invader clean + $(MAKE) -C calc clean src_only_full : $(MAKE) -C haribote src_only @@ -178,6 +182,7 @@ src_only_full : $(MAKE) -C notrec src_only $(MAKE) -C bball src_only $(MAKE) -C invader src_only + $(MAKE) -C calc src_only -$(DEL) haribote.img refresh : diff --git a/30_day/calc/!cons_9x.bat b/30_day/calc/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/calc/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/calc/!cons_nt.bat b/30_day/calc/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/calc/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/calc/Makefile b/30_day/calc/Makefile new file mode 100644 index 0000000..411c006 --- /dev/null +++ b/30_day/calc/Makefile @@ -0,0 +1,5 @@ +APP = calc +STACK = 4k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/calc/calc.c b/30_day/calc/calc.c new file mode 100644 index 0000000..cc3a31a --- /dev/null +++ b/30_day/calc/calc.c @@ -0,0 +1,163 @@ +#include "apilib.h" +#include /* sprintf */ + +#define INVALID -0x7fffffff + +int strtol(char *s, char **endp, int base); /* 标准函数 */ + +char *skipspace(char *p); +int getnum(char **pp, int priority); + +void HariMain(void) +{ + int i; + char s[30], *p; + + api_cmdline(s, 30); + for (p = s; *p > ' '; p++) { } /* 一直读到空格为止 */ + i = getnum(&p, 9); + if (i == INVALID) { + api_putstr0("error!\n"); + } else { + sprintf(s, "= %d = 0x%x\n", i, i); + api_putstr0(s); + } + api_end(); +} + +char *skipspace(char *p) +{ + for (; *p == ' '; p++) { } /* 将空格跳过去 */ + return p; +} + +int getnum(char **pp, int priority) +{ + char *p = *pp; + int i = INVALID, j; + p = skipspace(p); + + /*单项运算符*/ + if (*p == '+') { + p = skipspace(p + 1); + i = getnum(&p, 0); + } else if (*p == '-') { + p = skipspace(p + 1); + i = getnum(&p, 0); + if (i != INVALID) { + i = - i; + } + } else if (*p == '~') { + p = skipspace(p + 1); + i = getnum(&p, 0); + if (i != INVALID) { + i = ~i; + } + } else if (*p == '(') { /*括号*/ + p = skipspace(p + 1); + i = getnum(&p, 9); + if (*p == ')') { + p = skipspace(p + 1); + } else { + i = INVALID; + } + } else if ('0' <= *p && *p <= '9') { /*数值*/ + i = strtol(p, &p, 0); + } else { /*错误 */ + i = INVALID; + } + + /*二项运算符*/ + for (;;) { + if (i == INVALID) { + break; + } + p = skipspace(p); + if (*p == '+' && priority > 2) { + p = skipspace(p + 1); + j = getnum(&p, 2); + if (j != INVALID) { + i += j; + } else { + i = INVALID; + } + } else if (*p == '-' && priority > 2) { + p = skipspace(p + 1); + j = getnum(&p, 2); + if (j != INVALID) { + i -= j; + } else { + i = INVALID; + } + } else if (*p == '*' && priority > 1) { + p = skipspace(p + 1); + j = getnum(&p, 1); + if (j != INVALID) { + i *= j; + } else { + i = INVALID; + } + } else if (*p == '/' && priority > 1) { + p = skipspace(p + 1); + j = getnum(&p, 1); + if (j != INVALID && j != 0) { + i /= j; + } else { + i = INVALID; + } + } else if (*p == '%' && priority > 1) { + p = skipspace(p + 1); + j = getnum(&p, 1); + if (j != INVALID && j != 0) { + i %= j; + } else { + i = INVALID; + } + } else if (*p == '<' && p[1] == '<' && priority > 3) { + p = skipspace(p + 2); + j = getnum(&p, 3); + if (j != INVALID && j != 0) { + i <<= j; + } else { + i = INVALID; + } + } else if (*p == '>' && p[1] == '>' && priority > 3) { + p = skipspace(p + 2); + j = getnum(&p, 3); + if (j != INVALID && j != 0) { + i >>= j; + } else { + i = INVALID; + } + } else if (*p == '&' && priority > 4) { + p = skipspace(p + 1); + j = getnum(&p, 4); + if (j != INVALID) { + i &= j; + } else { + i = INVALID; + } + } else if (*p == '^' && priority > 5) { + p = skipspace(p + 1); + j = getnum(&p, 5); + if (j != INVALID) { + i ^= j; + } else { + i = INVALID; + } + } else if (*p == '|' && priority > 6) { + p = skipspace(p + 1); + j = getnum(&p, 6); + if (j != INVALID) { + i |= j; + } else { + i = INVALID; + } + } else { + break; + } + } + p = skipspace(p); + *pp = p; + return i; +} diff --git a/30_day/calc/make.bat b/30_day/calc/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/calc/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file From 72532c8cd7406f7d4bae1c73b7aacf0b9ddf73d1 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 20 May 2016 12:03:41 +0800 Subject: [PATCH 65/83] =?UTF-8?q?=E6=96=87=E6=9C=AC=E9=98=85=E8=A7=88?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 30_day/Makefile | 6 +- 30_day/tview/!cons_9x.bat | 1 + 30_day/tview/!cons_nt.bat | 1 + 30_day/tview/Makefile | 5 + 30_day/tview/make.bat | 1 + 30_day/tview/tview.c | 276 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 30_day/tview/!cons_9x.bat create mode 100644 30_day/tview/!cons_nt.bat create mode 100644 30_day/tview/Makefile create mode 100644 30_day/tview/make.bat create mode 100644 30_day/tview/tview.c diff --git a/30_day/Makefile b/30_day/Makefile index efee1ad..710ced7 100644 --- a/30_day/Makefile +++ b/30_day/Makefile @@ -23,7 +23,7 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb \ type/type.hrb iroha/iroha.hrb chklang/chklang.hrb \ notrec/notrec.hrb bball/bball.hrb invader/invader.hrb \ - calc/calc.hrb + calc/calc.hrb tview/tview.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:haribote/ipl20.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ @@ -56,6 +56,7 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ copy from:bball/bball.hrb to:@: \ copy from:invader/invader.hrb to:@: \ copy from:calc/calc.hrb to:@: \ + copy from:tview/tview.hrb to:@: \ copy from:nihongo/nihongo.fnt to:@: \ imgout:haribote.img @@ -100,6 +101,7 @@ full : $(MAKE) -C bball $(MAKE) -C invader $(MAKE) -C calc + $(MAKE) -C tview $(MAKE) haribote.img run_full : @@ -152,6 +154,7 @@ clean_full : $(MAKE) -C bball clean $(MAKE) -C invader clean $(MAKE) -C calc clean + $(MAKE) -C tview clean src_only_full : $(MAKE) -C haribote src_only @@ -183,6 +186,7 @@ src_only_full : $(MAKE) -C bball src_only $(MAKE) -C invader src_only $(MAKE) -C calc src_only + $(MAKE) -C tview src_only -$(DEL) haribote.img refresh : diff --git a/30_day/tview/!cons_9x.bat b/30_day/tview/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/tview/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/tview/!cons_nt.bat b/30_day/tview/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/tview/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/tview/Makefile b/30_day/tview/Makefile new file mode 100644 index 0000000..1ae00c8 --- /dev/null +++ b/30_day/tview/Makefile @@ -0,0 +1,5 @@ +APP = tview +STACK = 1024k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/tview/make.bat b/30_day/tview/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/tview/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/tview/tview.c b/30_day/tview/tview.c new file mode 100644 index 0000000..e9c7975 --- /dev/null +++ b/30_day/tview/tview.c @@ -0,0 +1,276 @@ +#include "apilib.h" + +#include + +int strtol(char *s, char **endp, int base); /* 标准函数 */ + +char *skipspace(char *p); +void textview(int win, int w, int h, int xskip, char *p, int tab, int lang); +char *lineview(int win, int w, int y, int xskip, unsigned char *p, int tab, int lang); +int puttab(int x, int w, int xskip, char *s, int tab); + +void HariMain(void) +{ + char winbuf[1024 * 757], txtbuf[240 * 1024]; + int w = 30, h = 10, t = 4, spd_x = 1, spd_y = 1; + int win, i, j, lang = api_getlang(), xskip = 0; + char s[30], *p, *q = 0, *r = 0; + + /*命令行解析*/ + api_cmdline(s, 30); + for (p = s; *p > ' '; p++) { } /*一直读到空格为止*/ + for (; *p != 0; ) { + p = skipspace(p); + if (*p == '-') { + if (p[1] == 'w') { + w = strtol(p + 2, &p, 0); + if (w < 20) { + w = 20; + } + if (w > 126) { + w = 126; + } + } else if (p[1] == 'h') { + h = strtol(p + 2, &p, 0); + if (h < 1) { + h = 1; + } + if (h > 45) { + h = 45; + } + } else if (p[1] == 't') { + t = strtol(p + 2, &p, 0); + if (t < 1) { + t = 4; + } + } else { +err: + api_putstr0(" >tview file [-w30 -h10 -t4]\n"); + api_end(); + } + } else { /*找到文件名*/ + if (q != 0) { + goto err; + } + q = p; + for (; *p > ' '; p++) { } /*一直读到空格为止*/ + r = p; + } + } + if (q == 0) { + goto err; + } + + /*准备窗口*/ + win = api_openwin(winbuf, w * 8 + 16, h * 16 + 37, -1, "tview"); + api_boxfilwin(win, 6, 27, w * 8 + 9, h * 16 + 30, 7); + + /*载入文件*/ + *r = 0; + i = api_fopen(q); + if (i == 0) { + api_putstr0("file open error.\n"); + api_end(); + } + j = api_fsize(i, 0); + if (j >= 240 * 1024 - 1) { + j = 240 * 1024 - 2; + } + txtbuf[0] = 0x0a; /*卫兵用的换行代码*/ + api_fread(txtbuf + 1, j, i); + api_fclose(i); + txtbuf[j + 1] = 0; + q = txtbuf + 1; + for (p = txtbuf + 1; *p != 0; p++) { /*为了让处理变得简单,删掉0x0d的代码*/ + if (*p != 0x0d) { + *q = *p; + q++; + } + } + *q = 0; + + /*主体*/ + p = txtbuf + 1; + for (;;) { + textview(win, w, h, xskip, p, t, lang); + i = api_getkey(1); + if (i == 'Q' || i == 'q') { + api_end(); + } + if ('A' <= i && i <= 'F') { + spd_x = 1 << (i - 'A'); /* 1, 2, 4, 8, 16, 32 */ + } + if ('a' <= i && i <= 'f') { + spd_y = 1 << (i - 'a'); /* 1, 2, 4, 8, 16, 32 */ + } + if (i == '<' && t > 1) { + t /= 2; + } + if (i == '>' && t < 256) { + t *= 2; + } + if (i == '4') { + for (;;) { + xskip -= spd_x; + if (xskip < 0) { + xskip = 0; + } + if (api_getkey(0) != '4') { /*如果没有按下“4”则处理结束*/ + break; + } + } + } + if (i == '6') { + for (;;) { + xskip += spd_x; + if (api_getkey(0) != '6') { + break; + } + } + } + if (i == '8') { + for (;;) { + for (j = 0; j < spd_y; j++) { + if (p == txtbuf + 1) { + break; + } + for (p--; p[-1] != 0x0a; p--) { } /*回溯到上一个字符为0x0a为止*/ + } + if (api_getkey(0) != '8') { + break; + } + } + } + if (i == '2') { + for (;;) { + for (j = 0; j < spd_y; j++) { + for (q = p; *q != 0 && *q != 0x0a; q++) { } + if (*q == 0) { + break; + } + p = q + 1; + } + if (api_getkey(0) != '2') { + break; + } + } + } + } +} + +char *skipspace(char *p) +{ + for (; *p == ' '; p++) { } /*跳过空格*/ + return p; +} + +void textview(int win, int w, int h, int xskip, char *p, int tab, int lang) +{ + int i; + api_boxfilwin(win + 1, 8, 29, w * 8 + 7, h * 16 + 28, 7); + for (i = 0; i < h; i++) { + p = lineview(win, w, i * 16 + 29, xskip, p, tab, lang); + } + api_refreshwin(win, 8, 29, w * 8 + 8, h * 16 + 29); + return; +} + +char *lineview(int win, int w, int y, int xskip, unsigned char *p, int tab, int lang) +{ + int x = - xskip; + char s[130]; + for (;;) { + if (*p == 0) { + break; + } + if (*p == 0x0a) { + p++; + break; + } + if (lang == 0) { /* ASCII */ + if (*p == 0x09) { + x = puttab(x, w, xskip, s, tab); + } else { + if (0 <= x && x < w) { + s[x] = *p; + } + x++; + } + p++; + } + if (lang == 1) { /* SJIS */ + if (*p == 0x09) { + x = puttab(x, w, xskip, s, tab); + p++; + } else if ((0x81 <= *p && *p <= 0x9f) || (0xe0 <= *p && *p <= 0xfc)) { + /*全角字符*/ + if (x == -1) { + s[0] = ' '; + } + if (0 <= x && x < w - 1) { + s[x] = *p; + s[x + 1] = p[1]; + } + if (x == w - 1) { + s[x] = ' '; + } + x += 2; + p += 2; + } else { + if (0 <= x && x < w) { + s[x] = *p; + } + x++; + p++; + } + } + if (lang == 2) { /* EUC */ + if (*p == 0x09) { + x = puttab(x, w, xskip, s, tab); + p++; + } else if (0xa1 <= *p && *p <= 0xfe) { + /*全角字符*/ + if (x == -1) { + s[0] = ' '; + } + if (0 <= x && x < w - 1) { + s[x] = *p; + s[x + 1] = p[1]; + } + if (x == w - 1) { + s[x] = ' '; + } + x += 2; + p += 2; + } else { + if (0 <= x && x < w) { + s[x] = *p; + } + x++; + p++; + } + } + } + if (x > w) { + x = w; + } + if (x > 0) { + s[x] = 0; + api_putstrwin(win + 1, 8, y, 0, x, s); + } + return p; +} + +int puttab(int x, int w, int xskip, char *s, int tab) +{ + for (;;) { + if (0 <= x && x < w) { + s[x] = ' '; + } + x++; + if ((x + xskip) % tab == 0) { + break; + } + } + return x; +} From b2d31a8e54644b4416befefa069a958cdd2fd4d0 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 20 May 2016 13:38:43 +0800 Subject: [PATCH 66/83] =?UTF-8?q?MML=E6=92=AD=E6=94=BE=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 30_day/Makefile | 10 +- 30_day/mmldata/daigo.mml | Bin 0 -> 487 bytes 30_day/mmldata/daigo.org | 30 ++++ 30_day/mmldata/daiku.mml | Bin 0 -> 358 bytes 30_day/mmldata/daiku.org | 17 +++ 30_day/mmldata/fujisan.mml | Bin 0 -> 302 bytes 30_day/mmldata/fujisan.org | 15 ++ 30_day/mmldata/kirakira.mml | Bin 0 -> 195 bytes 30_day/mmldata/kirakira.org | 13 ++ 30_day/mmlplay/!cons_9x.bat | 1 + 30_day/mmlplay/!cons_nt.bat | 1 + 30_day/mmlplay/Makefile | 5 + 30_day/mmlplay/make.bat | 1 + 30_day/mmlplay/mmlplay.c | 271 ++++++++++++++++++++++++++++++++++++ 14 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 30_day/mmldata/daigo.mml create mode 100644 30_day/mmldata/daigo.org create mode 100644 30_day/mmldata/daiku.mml create mode 100644 30_day/mmldata/daiku.org create mode 100644 30_day/mmldata/fujisan.mml create mode 100644 30_day/mmldata/fujisan.org create mode 100644 30_day/mmldata/kirakira.mml create mode 100644 30_day/mmldata/kirakira.org create mode 100644 30_day/mmlplay/!cons_9x.bat create mode 100644 30_day/mmlplay/!cons_nt.bat create mode 100644 30_day/mmlplay/Makefile create mode 100644 30_day/mmlplay/make.bat create mode 100644 30_day/mmlplay/mmlplay.c diff --git a/30_day/Makefile b/30_day/Makefile index 710ced7..0853d9d 100644 --- a/30_day/Makefile +++ b/30_day/Makefile @@ -23,7 +23,7 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb \ type/type.hrb iroha/iroha.hrb chklang/chklang.hrb \ notrec/notrec.hrb bball/bball.hrb invader/invader.hrb \ - calc/calc.hrb tview/tview.hrb + calc/calc.hrb tview/tview.hrb mmlplay/mmlplay.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:haribote/ipl20.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ @@ -57,6 +57,11 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ copy from:invader/invader.hrb to:@: \ copy from:calc/calc.hrb to:@: \ copy from:tview/tview.hrb to:@: \ + copy from:mmlplay/mmlplay.hrb to:@: \ + copy from:mmldata/kirakira.mml to:@: \ + copy from:mmldata/fujisan.mml to:@: \ + copy from:mmldata/daigo.mml to:@: \ + copy from:mmldata/daiku.mml to:@: \ copy from:nihongo/nihongo.fnt to:@: \ imgout:haribote.img @@ -102,6 +107,7 @@ full : $(MAKE) -C invader $(MAKE) -C calc $(MAKE) -C tview + $(MAKE) -C mmlplay $(MAKE) haribote.img run_full : @@ -155,6 +161,7 @@ clean_full : $(MAKE) -C invader clean $(MAKE) -C calc clean $(MAKE) -C tview clean + $(MAKE) -C mmlplay clean src_only_full : $(MAKE) -C haribote src_only @@ -187,6 +194,7 @@ src_only_full : $(MAKE) -C invader src_only $(MAKE) -C calc src_only $(MAKE) -C tview src_only + $(MAKE) -C mmlplay src_only -$(DEL) haribote.img refresh : diff --git a/30_day/mmldata/daigo.mml b/30_day/mmldata/daigo.mml new file mode 100644 index 0000000000000000000000000000000000000000..57337fed7acb83722bd68e13ae20677795ccee12 GIT binary patch literal 487 zcmVC*Y+EtG!x8h~L>go*%VfgI7nWmR2lqaw~wZq)n4GsC_*nEVo1D$%hvbEIL^C^8E zLq`3_VMmD*T6tVgAdcXeQo#IbklKD>cdBhbIyB23%*E$P**2@YDL!P;{Ft0{E>c=2 z0>2UHx_P^ZX4gNPaszWlm-ON(O#tD0*{~vpY+c*@gQ8C(Z-cV{Rrs=Jo~j&u;(RhE z6<>K**6@$L85*kG?gtpW!(;*XO|L;vY7CCoF(Zj3F97B?Q*LQp(RAIb?x%i%N&h+ zoKKQP?aYuV!D_L5-l^K8zNntgndOj3-h0wvm&!48L&KDuAmRDqvZvo37T?Zw6cr+mK1U8b$&7wu! z2QwKFDlpd56zWbf1P^}oGbXz!izls}E-E-E-C8&C2FFFD8&D2GGF +Q8E-Q7Q7GGFQ8E-Q7GGFL4E-RCRG2.L8R>E-A-A-A-Q8FQ7DDDQ8>E-G>CCQ8C2Q7DQ8D2Q7CCCE-Q8E-Q7DQ4DF +Q8FQ7EQ4EGQ7GQ7FQ4FA-Q8A-Q7GQ4GB-Q8B-Q7A-Q4A->C +Q8CQ7DQ7CE-E-E-C>>FDD +CCC>>E-E-E- +CL4B->E-DE-FQ7CQ8CQ7E-DE-FQ7CQ8CQ7B->E-DE-FQ7CQ8CCD-Q7CQ8CD-E-FQ7E- +Q8D-E-D-Q7CQ8E-FG-FE-Q7FQ8G-FE-Q7FQ8G-F +E-Q7FQ8G-FE-FG-FG-Q7AL8B-&B-2Q4>CDQ7CQ4CQ7>AB-A +B-AB-Q7AQ4B->CDQ7CQ4CQ7B->B-B-E-GGGE-DDDQ8E-Q7>GGGE-B-B-B-B-4R4.B-B-B-B-4R4.>DDDE-4 +R1R4 diff --git a/30_day/mmldata/daiku.mml b/30_day/mmldata/daiku.mml new file mode 100644 index 0000000000000000000000000000000000000000..f2d320f189a820ef1f48569ecb77e0d39addd77b GIT binary patch literal 358 zcmV-s0h#`Z|Ns910000_Q$bTpLrqW$1qA`FuseE$z^GZk(i3eTMRk$|TI_Y|QF?vT z2`6Q$$+r1KC@AB7+T5Or$pkM!&U`ww%Su*SiTeQudgMs`{3<+8%eS8O?PzF{B%AV7 z!e;sF%_Oo?hU};^)g%=|>@lT1 z2jrf3M5h88yZw&9kOre6U#CEBgccdoH_5M@pJ4=g&YB;Wmbv&aZG^n!0Kn>&{l{L3 zKM5~Q<-$B47i_L;rzm(DRs*c0`YfI+JJ^LI3~& literal 0 HcmV?d00001 diff --git a/30_day/mmldata/daiku.org b/30_day/mmldata/daiku.org new file mode 100644 index 0000000..abf86fc --- /dev/null +++ b/30_day/mmldata/daiku.org @@ -0,0 +1,17 @@ +/* uȑ9 jZ "" op.125v Ludwig van Beethoven 씪쎌 */ + +$E"SJIS"; T110L4 + + O4 +$K"ꂽ‹ Y_"; F+F+GA AGF+E DDEF+ F+.E8E2 +$K"͉̂ тɐX"; F+F+GA AGF+E DDEF+ E.D8D2 +$K"S͑u₩ і"; EEF+D EF+8G8F+D EF+8G8F+E DE +$K"킷 邫Ί"; F+& F+F+GA AGF+E DDEF+ E.D8D2 + + O5 +$K"ԍ炭uׂ eF"; F+F+GA AGF+E DDEF+ F+.E8E2 +$K"u₩ ݂Ȃz˂"; F+F+GA AGF+E DDEF+ E.D8D2 +$K"S͉₩ K"; EEF+D EF+8G8F+D EF+8G8F+E DE +$K"͉ т̉"; F+& F+F+GA AGF+E DDEF+ E.D8D2 + +$K""; R1 diff --git a/30_day/mmldata/fujisan.mml b/30_day/mmldata/fujisan.mml new file mode 100644 index 0000000000000000000000000000000000000000..fc9a778a0c59ad8d5d562259c33ad9ae273c9008 GIT binary patch literal 302 zcmV+}0nz@6|Ns910000_Q$bTpLrqW!F$Dp(FAkDb0 z=3*SoEOVcNEW3IrX^QQg{g6xU=#OjeM0H>`(^>E>&@P}kmSm~l+8y7yE&hYSg;aNO zj+71hONrS){G!(tLwS{ljr1N*BlAH>c1Lb(%46F1E+ZpwtqgI+waT2wad}cvl7}Go zyEvSYvp4U_vAzO6={%_)y5BXOI{uCr0b~oe0nYMQ=f~fk^Qcm A_y7O^ literal 0 HcmV?d00001 diff --git a/30_day/mmldata/fujisan.org b/30_day/mmldata/fujisan.org new file mode 100644 index 0000000..23c1fe6 --- /dev/null +++ b/30_day/mmldata/fujisan.org @@ -0,0 +1,15 @@ +/* uxmRv ȏ ޒJg쎌 */ + +$E"SJIS"; T120L4O4 + +$K"܂_̏ɏo"; G.G8AGEC8D8E2 D.G8GF8E8D2.R +$K"l̎R낵"; G.G8ECA.B8>CCC2CCC2f+jv#ZsD*(Svkn)UCL!_@Jk1o zFhR~_yI+^E9?;(x@d$k!q{SU6O%@LONU4trk5d<{7oTh07iH6#R#o)@W4tY?B2BcW;2kr-^P+1%9z3A6yOf#msNx`;;U_b literal 0 HcmV?d00001 diff --git a/30_day/mmldata/kirakira.org b/30_day/mmldata/kirakira.org new file mode 100644 index 0000000..85f5a62 --- /dev/null +++ b/30_day/mmldata/kirakira.org @@ -0,0 +1,13 @@ +/* u炫琯v tXw xq쎌 */ + +$E"SJIS"; T120L4O4 + +$K"炫Ђ ̐"; CCGGAAG2 FFEEDDC2 +$K"܂΂Ă ݂ȂĂ"; GGFFEED2 GGFFEED2 +$K"炫Ђ ̐"; CCGGAAG2 FFEEDDC2 +$K""; R1 + +$K"炫Ђ ̐"; CCGGAAG2 FFEEDDC2 +$K"݂Ȃ̉̂ ͂Ƃ"; GGFFEED2 GGFFEED2 +$K"炫Ђ ̐"; CCGGAAG2 FFEEDDC2 +$K""; R1 R1 diff --git a/30_day/mmlplay/!cons_9x.bat b/30_day/mmlplay/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/mmlplay/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/mmlplay/!cons_nt.bat b/30_day/mmlplay/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/mmlplay/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/mmlplay/Makefile b/30_day/mmlplay/Makefile new file mode 100644 index 0000000..ad3f1fe --- /dev/null +++ b/30_day/mmlplay/Makefile @@ -0,0 +1,5 @@ +APP = mmlplay +STACK = 132k +MALLOC = 0k + +include ../app_make.txt diff --git a/30_day/mmlplay/make.bat b/30_day/mmlplay/make.bat new file mode 100644 index 0000000..6b0dbfc --- /dev/null +++ b/30_day/mmlplay/make.bat @@ -0,0 +1 @@ +..\..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/30_day/mmlplay/mmlplay.c b/30_day/mmlplay/mmlplay.c new file mode 100644 index 0000000..0e4254c --- /dev/null +++ b/30_day/mmlplay/mmlplay.c @@ -0,0 +1,271 @@ +#include "apilib.h" + +#include /* strlen */ + +int strtol(char *s, char **endp, int base); /*标准函数 */ + +void waittimer(int timer, int time); +void end(char *s); + +void HariMain(void) +{ + char winbuf[256 * 112], txtbuf[100 * 1024]; + char s[32], *p, *r; + int win, timer, i, j, t = 120, l = 192 / 4, o = 4, q = 7, note_old = 0; + + /*音号与频率(mHz)的对照表*/ + /*例如,04A为440Hz,即440000 */ + /*第16八度的A为1802240Hz,即1802240000 */ + /*以下为第16八度的列表(C~B) */ + static int tonetable[12] = { + 1071618315, 1135340056, 1202850889, 1274376125, 1350154473, 1430438836, + 1515497155, 1605613306, 1701088041, 1802240000, 1909406767, 2022946002 + }; + static int notetable[7] = { +9, +11, +0 /* C */, +2, +4, +5, +7 }; + + /*命令行解析*/ + api_cmdline(s, 30); + for (p = s; *p > ' '; p++) { } /*一直读到空格为止*/ + for (; *p == ' '; p++) { } /*跳过空格*/ + i = strlen(p); + if (i > 12) { +file_error: + end("file open error.\n"); + } + if (i == 0) { + end(0); + } + + /*准备窗口*/ + win = api_openwin(winbuf, 256, 112, -1, "mmlplay"); + api_putstrwin(win, 128, 32, 0, i, p); + api_boxfilwin(win, 8, 60, 247, 76, 7); + api_boxfilwin(win, 6, 86, 249, 105, 7); + + /*载入文件*/ + i = api_fopen(p); + if (i == 0) { + goto file_error; + } + j = api_fsize(i, 0); + if (j >= 100 * 1024) { + j = 100 * 1024 - 1; + } + api_fread(txtbuf, j, i); + api_fclose(i); + txtbuf[j] = 0; + r = txtbuf; + i = 0; /*通常模式*/ + for (p = txtbuf; *p != 0; p++) { /*为了方便处理,将注释和空白删去*/ + if (i == 0 && *p > ' ') { /*不是空格或换行符*/ + if (*p == '/') { + if (p[1] == '*') { + i = 1; + } else if (p[1] == '/') { + i = 2; + } else { + *r = *p; + if ('a' <= *p && *p <= 'z') { + *r += 'A' - 'a'; /*将小写字母转换为大写字母*/ + } + r++; + } + } else if (*p == 0x22) { + *r = *p; + r++; + i = 3; + } else { + *r = *p; + r++; + } + } else if (i == 1 && *p == '*' && p[1] == '/') { /*段注释*/ + p++; + i = 0; + } else if (i == 2 && *p == 0x0a) { /*行注释*/ + i = 0; + } else if (i == 3) { /*字符串*/ + *r = *p; + r++; + if (*p == 0x22) { + i = 0; + } else if (*p == '%') { + p++; + *r = *p; + r++; + } + } + } + *r = 0; + + /*定时器准备*/ + timer = api_alloctimer(); + api_inittimer(timer, 128); + + /*主体*/ + p = txtbuf; + for (;;) { + if (('A' <= *p && *p <= 'G') || *p == 'R') { /*音符、休止符*/ + /*计算频率*/ + if (*p == 'R') { + i = 0; + s[0] = 0; + } else { + i = o * 12 + notetable[*p - 'A'] + 12; + s[0] = 'O'; + s[1] = '0' + o; + s[2] = *p; + s[3] = ' '; + s[4] = 0; + } + p++; + if (*p == '+' || *p == '-' || *p == '#') { + s[3] = *p; + if (*p == '-') { + i--; + } else { + i++; + } + p++; + } + if (i != note_old) { + api_boxfilwin(win + 1, 32, 36, 63, 51, 8); + if (s[0] != 0) { + api_putstrwin(win + 1, 32, 36, 10, 4, s); + } + api_refreshwin(win, 32, 36, 64, 52); + if (28 <= note_old && note_old <= 107) { + api_boxfilwin(win, (note_old - 28) * 3 + 8, 60, (note_old - 28) * 3 + 10, 76, 7); + } + if (28 <= i && i <= 107) { + api_boxfilwin(win, (i - 28) * 3 + 8, 60, (i - 28) * 3 + 10, 76, 4); + } + if (s[0] != 0) { + api_beep(tonetable[i % 12] >> (17 - i / 12)); + } else { + api_beep(0); + } + note_old = i; + } + /*音长计算*/ + if ('0' <= *p && *p <= '9') { + i = 192 / strtol(p, &p, 10); + } else { + i = l; + } + for (; *p == '.'; ) { + p++; + i += i / 2; + } + i *= (60 * 100 / 48); + i /= t; + if (s[0] != 0 && q < 8 && *p != '&') { + j = i * q / 8; + waittimer(timer, j); + api_boxfilwin(win, 32, 36, 63, 51, 8); + if (28 <= note_old && note_old <= 107) { + api_boxfilwin(win, (note_old - 28) * 3 + 8, 60, (note_old - 28) * 3 + 10, 76, 7); + } + note_old = 0; + api_beep(0); + } else { + j = 0; + if (*p == '&') { + p++; + } + } + waittimer(timer, i - j); + } else if (*p == '<') { /*八度-- */ + p++; + o--; + } else if (*p == '>') { /*八度++ */ + p++; + o++; + } else if (*p == 'O') { /*八度指定*/ + o = strtol(p + 1, &p, 10); + } else if (*p == 'Q') { /* Q参数指定*/ + q = strtol(p + 1, &p, 10); + } else if (*p == 'L') { /*默认音长指定*/ + l = strtol(p + 1, &p, 10); + if (l == 0) { + goto syntax_error; + } + l = 192 / l; + for (; *p == '.'; ) { + p++; + l += l / 2; + } + } else if (*p == 'T') { /*速度指定*/ + t = strtol(p + 1, &p, 10); + } else if (*p == '$') { /*扩展命令*/ + if (p[1] == 'K') { /*卡拉OK命令*/ + p += 2; + for (; *p != 0x22; p++) { + if (*p == 0) { + goto syntax_error; + } + } + p++; + for (i = 0; i < 32; i++) { + if (*p == 0) { + goto syntax_error; + } + if (*p == 0x22) { + break; + } + if (*p == '%') { + s[i] = p[1]; + p += 2; + } else { + s[i] = *p; + p++; + } + } + if (i > 30) { + end("karaoke too long.\n"); + } + api_boxfilwin(win + 1, 8, 88, 247, 103, 7); + s[i] = 0; + if (i != 0) { + api_putstrwin(win + 1, 128 - i * 4, 88, 0, i, s); + } + api_refreshwin(win, 8, 88, 248, 104); + } + for (; *p != ';'; p++) { + if (*p == 0) { + goto syntax_error; + } + } + p++; + } else if (*p == 0) { + p = txtbuf; + } else { +syntax_error: + end("mml syntax error.\n"); + } + } +} + +void waittimer(int timer, int time) +{ + int i; + api_settimer(timer, time); + for (;;) { + i = api_getkey(1); + if (i == 'Q' || i == 'q') { + api_beep(0); + api_end(); + } + if (i == 128) { + return; + } + } +} + +void end(char *s) +{ + if (s != 0) { + api_putstr0(s); + } + api_beep(0); + api_end(); +} From 08d19d7512b030fa3eb1961c4baa454b9570dd53 Mon Sep 17 00:00:00 2001 From: Yourtion Date: Fri, 20 May 2016 14:05:13 +0800 Subject: [PATCH 67/83] =?UTF-8?q?=E5=9B=BE=E7=89=87=E9=98=85=E8=A7=88?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 30_day/Makefile | 8 +- 30_day/gview/!cons_9x.bat | 1 + 30_day/gview/!cons_nt.bat | 1 + 30_day/gview/Makefile | 90 +++++ 30_day/gview/bmp.nasm | 646 ++++++++++++++++++++++++++++++ 30_day/gview/bmp.obj | Bin 0 -> 4292 bytes 30_day/gview/gview.c | 121 ++++++ 30_day/gview/jpeg.c | 733 +++++++++++++++++++++++++++++++++++ 30_day/gview/make.bat | 1 + 30_day/pictdata/fujisan.jpg | Bin 0 -> 15297 bytes 30_day/pictdata/fujisan_.jpg | Bin 0 -> 15978 bytes 30_day/pictdata/night.bmp | Bin 0 -> 666 bytes 30_day/pictdata/night_.bmp | Bin 0 -> 8310 bytes 13 files changed, 1600 insertions(+), 1 deletion(-) create mode 100644 30_day/gview/!cons_9x.bat create mode 100644 30_day/gview/!cons_nt.bat create mode 100644 30_day/gview/Makefile create mode 100644 30_day/gview/bmp.nasm create mode 100644 30_day/gview/bmp.obj create mode 100644 30_day/gview/gview.c create mode 100644 30_day/gview/jpeg.c create mode 100644 30_day/gview/make.bat create mode 100644 30_day/pictdata/fujisan.jpg create mode 100644 30_day/pictdata/fujisan_.jpg create mode 100644 30_day/pictdata/night.bmp create mode 100644 30_day/pictdata/night_.bmp diff --git a/30_day/Makefile b/30_day/Makefile index 0853d9d..d54fa0c 100644 --- a/30_day/Makefile +++ b/30_day/Makefile @@ -23,7 +23,7 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ sosu/sosu.hrb sosu2/sosu2.hrb sosu3/sosu3.hrb \ type/type.hrb iroha/iroha.hrb chklang/chklang.hrb \ notrec/notrec.hrb bball/bball.hrb invader/invader.hrb \ - calc/calc.hrb tview/tview.hrb mmlplay/mmlplay.hrb + calc/calc.hrb tview/tview.hrb mmlplay/mmlplay.hrb gview/gview.hrb $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:haribote/ipl20.bin len:512 from:0 to:0 \ copy from:haribote/haribote.sys to:@: \ @@ -62,6 +62,9 @@ haribote.img : haribote/ipl20.bin haribote/haribote.sys Makefile \ copy from:mmldata/fujisan.mml to:@: \ copy from:mmldata/daigo.mml to:@: \ copy from:mmldata/daiku.mml to:@: \ + copy from:gview/gview.hrb to:@: \ + copy from:pictdata/fujisan.jpg to:@: \ + copy from:pictdata/night.bmp to:@: \ copy from:nihongo/nihongo.fnt to:@: \ imgout:haribote.img @@ -108,6 +111,7 @@ full : $(MAKE) -C calc $(MAKE) -C tview $(MAKE) -C mmlplay + $(MAKE) -C gview $(MAKE) haribote.img run_full : @@ -162,6 +166,7 @@ clean_full : $(MAKE) -C calc clean $(MAKE) -C tview clean $(MAKE) -C mmlplay clean + $(MAKE) -C gview clean src_only_full : $(MAKE) -C haribote src_only @@ -195,6 +200,7 @@ src_only_full : $(MAKE) -C calc src_only $(MAKE) -C tview src_only $(MAKE) -C mmlplay src_only + $(MAKE) -C gview src_only -$(DEL) haribote.img refresh : diff --git a/30_day/gview/!cons_9x.bat b/30_day/gview/!cons_9x.bat new file mode 100644 index 0000000..e42252a --- /dev/null +++ b/30_day/gview/!cons_9x.bat @@ -0,0 +1 @@ +command \ No newline at end of file diff --git a/30_day/gview/!cons_nt.bat b/30_day/gview/!cons_nt.bat new file mode 100644 index 0000000..6e07473 --- /dev/null +++ b/30_day/gview/!cons_nt.bat @@ -0,0 +1 @@ +cmd.exe \ No newline at end of file diff --git a/30_day/gview/Makefile b/30_day/gview/Makefile new file mode 100644 index 0000000..917f0a7 --- /dev/null +++ b/30_day/gview/Makefile @@ -0,0 +1,90 @@ +APP = gview +STACK = 4480k +MALLOC = 0k + +TOOLPATH = ../../z_tools/ +INCPATH = ../../z_tools/haribote/ +APILIBPATH = ../apilib/ +HARIBOTEPATH = ../haribote/ + +MAKE = $(TOOLPATH)make.exe -r +NASK = $(TOOLPATH)nask.exe +CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -I../ -Os -Wall -quiet +GAS2NASK = $(TOOLPATH)gas2nask.exe -a +OBJ2BIM = $(TOOLPATH)obj2bim.exe +MAKEFONT = $(TOOLPATH)makefont.exe +BIN2OBJ = $(TOOLPATH)bin2obj.exe +BIM2HRB = $(TOOLPATH)bim2hrb.exe +BIM2BIN = $(TOOLPATH)bim2bin.exe +RULEFILE = ../haribote.rul +EDIMG = $(TOOLPATH)edimg.exe +IMGTOL = $(TOOLPATH)imgtol.com +GOLIB = $(TOOLPATH)golib00.exe +COPY = copy +DEL = del + +#默认动作 + +default : + $(MAKE) $(APP).hrb + +#文件生成规则 + +$(APP).bim : $(APP).obj bmp.obj jpeg.obj $(APILIBPATH)apilib.lib Makefile + $(OBJ2BIM) @$(RULEFILE) out:$(APP).bim map:$(APP).map stack:$(STACK) \ + $(APP).obj jpeg.obj bmp.obj $(APILIBPATH)apilib.lib + +haribote.img : ../haribote/ipl20.bin ../haribote/haribote.sys $(APP).hrb \ + Makefile + $(EDIMG) imgin:../../z_tools/fdimg0at.tek \ + wbinimg src:../haribote/ipl20.bin len:512 from:0 to:0 \ + copy from:../haribote/haribote.sys to:@: \ + copy from:$(APP).hrb to:@: \ + copy from:../nihongo/nihongo.fnt to:@: \ + imgout:haribote.img + +# 其他指令 + +%.gas : %.c ../apilib.h Makefile + $(CC1) -o $*.gas $*.c + +%.nas : %.gas Makefile + $(GAS2NASK) $*.gas $*.nas + +%.obj : %.nas Makefile + $(NASK) $*.nas $*.obj $*.lst + +%.org : %.bim Makefile + $(BIM2HRB) $*.bim $*.org $(MALLOC) + +%.hrb : %.org Makefile + $(BIM2BIN) -osacmp in:$*.org out:$*.hrb + +# 运行程序 + +run : + $(MAKE) haribote.img + $(COPY) haribote.img ..\..\z_tools\qemu\fdimage0.bin + $(MAKE) -C ../../z_tools/qemu + +full : + $(MAKE) -C $(APILIBPATH) + $(MAKE) $(APP).hrb + +run_full : + $(MAKE) -C $(APILIBPATH) + $(MAKE) -C ../haribote + $(MAKE) run + +clean : + -$(DEL) *.lst + -$(DEL) gview.obj + -$(DEL) jpeg.obj + -$(DEL) *.map + -$(DEL) *.bim + -$(DEL) *.org + -$(DEL) haribote.img + +src_only : + $(MAKE) clean + -$(DEL) $(APP).hrb diff --git a/30_day/gview/bmp.nasm b/30_day/gview/bmp.nasm new file mode 100644 index 0000000..e6c0243 --- /dev/null +++ b/30_day/gview/bmp.nasm @@ -0,0 +1,646 @@ +; BMP decode routine by I.Tak. 2003 + +section .text align=1 +[bits 32] +;BMP File Structure (I can't understand MS.) + + struc BMP + ;FILE HEADER +.fType: resw 1 ;BM +.fSize: resd 1 ;whole file size + resd 1 ;reserved +.fOffBits: resd 1 ;offset from file top to image + ;INFO HEADER +.iSize: resd 1 ;INFO HEADER size +.iWidth: resd 1 ;Image Width in pixels +.iHeight: resd 1 ;Image Height in pixels +.iPlanes: resw 1 ;must be 1 +.iBitCount: resw 1 ;BitPerPixel 1, 4, 8, 24 (and 15,16 for new OS/2 ?) +.iCompression: resd 1 ;Compress Type. 0 for none, then SizeImage=0 +.iSizeImage: resd 1 ;Image Size(compressed) +.iXPPM: resd 1 ;X Pixel Per Meter +.iYPPM: resd 1 +.iClrUsed: resd 1 ;Number of used ColorQuad (0 for whole Quad) +.iClrImportant: resd 1 ;Number of Important ColorQuad. + endstruc + + struc BMPOS2 + ;FILE HEADER +.fType: resw 1 ;BM +.fSize: resd 1 ;whole file size + resd 1 ;reserved +.fOffBits: resd 1 ;offset from file top to image + ;CORE HEADER +.iSize: resd 1 ;CORE HEADER size +.iWidth: resw 1 ;Image Width in pixels +.iHeight: resw 1 ;Image Height in pixels +.iPlanes: resw 1 ;must be 1 +.iBitCount: resw 1 ;BitPerPixel 1, 4, 8, 24 (and 15,16 for new OS/2 ?) + endstruc + +; B/W bmp can also have palettes. The first for 0, second for 1. + + struc CQuad +.b: resb 1 +.g: resb 1 +.r: resb 1 + resb 1 ;reserved + endstruc + + +%if 0 +int info_BMP(struct DLL_STRPICENV *env, int *info, int size, UCHAR *fp); +/* 1 (0?), Ԥ0 */ +int decode0_BMP(struct DLL_STRPICENV *env, int size, UCHAR *fp, + int b_type, UCHAR *buf, int skip); +/* 顼ɤ֤Ȥꤢ0ˤƤ */ +env64KBΥꥢǤ롣Ƭ8dw֤ѤˤʤäƤ롣 +ȯ餷, 󥹥ѿŪˤϻȤʤ褦JPEG_init +base_imgΤdecodeΤȤǤȻפ +%endif + +[absolute 0] ;naskʤ[section .bss] org 0 win32ᤫ +bmpinfo: +.regs: resd 4 +.reteip: resd 1 +.env: resd 1 +.info: resd 1 +.size: resd 1 +.module: resd 1 +[absolute 0] +info: +.type: resd 1 ;1 for BMP, 2 for JPEG + resd 1 ;0 +.width: resd 1 +.height: resd 1 +[section .text] +[global _info_BMP] +_info_BMP: + push ebx + push ebp + push esi + push edi + mov esi, [esp+bmpinfo.module] + mov eax, [esp+bmpinfo.size] + call bmpHeader + test edi, edi + jz .ret + mov esi, [esp+bmpinfo.info] + mov [esi+info.width], eax + mov [esi+info.height], ecx + mov [esi+info.type], edi ;=1 + dec edi + mov [esi+info.type+4], edi ;=0 + inc edi +.ret: mov eax, edi + pop edi + pop esi + pop ebp + pop ebx + ret + +;in: esi=module, eax=size +;ret:eax=width, ecx=hegiht, edx=paletteSize, ebx=palette +; ebp=bpp, esi=endOfImage, edi=successFlag +bmpHeader: + lea edx, [esi+eax] ;moduleEnd + xor edi, edi + push edx + xor edx, edx + + cmp eax, byte BMP.iSize+4 + jbe ..@ret ;ѤƤޤ + cmp word[esi],'BM' + je .notMAC + sub esi, byte -128 + add eax, byte -128 + pop ebx + push eax + cmp eax, byte BMP.iSize+4 +..@ret: jbe .ret + cmp word[esi], 'BM' + jne .ret +.notMAC: + ;;MS,OS/2 եޥåȳǧ + mov ecx, [esi +BMP.iSize] + cmp ecx, byte 12 ;OS/2 format. + jne .MS + cmp eax, byte BMPOS2_size + jbe .ret ;coreإåʤ + lea ebx, [esi+ecx+14] ;palette + movzx eax, word[esi+BMPOS2.iWidth] ;width + movzx ecx, word[esi+BMPOS2.iHeight] ;height + movzx ebp, word[esi+BMPOS2.iBitCount] ;bpp + mov dl, 3 ;paletteSize + jmp short .endif +.MS: cmp eax, byte BMP_size + jbe .ret ;infoإåʤ + lea ebx, [esi+ecx+14] + sub ecx,byte 40 + jne .ret ;unknownFormat + cmp ecx, [esi+BMP.iCompression] + jne .ret ;Compressed. + mov eax, [esi+BMP.iWidth] ;width + mov ecx, [esi+BMP.iHeight] ;height + movzx ebp, word[esi +BMP.iBitCount] ;bpp + mov dl, 4 ;paletteSize +.endif: + add esi, [esi +BMP.fOffBits] + + ;sizeheightäƤǤ + ;ɤ٤ϥ顼 + push edx + push eax + mul ebp ;eax=width*bpp + add eax, byte 7 + shr eax, 3 ;lineSizeWithoutPudding + mov edx, eax + add eax, byte 3 ;size<1GBꤷedx̵ + and al, -4 ;lineSizeWithPudding + sub edx, eax ;-puddingSize + push edx + mul ecx + pop edx + add esi, eax + add esi, edx ;ǽԤκǸˤpuddingʤȸ٤ + cmp esi, [esp+8] ;endOfModule + pop eax + ja .ret2 + sub esi, edx ;esi=endOfImage + inc edi ;succeeded! +.ret2: pop edx +.ret: add esp, byte 4 + ret + +;*************************************************************** +; ͥǺäƤ뤬, ®ͥǺäΤΤꤤ⡣ +; ʼι®⡼ɤΤߺäƤ + +[absolute 0] +decode: +.regs: resd 4 +.reteip: resd 1 +.env: resd 1 +.size: resd 1 +.module: resd 1 +.outputType: resd 1 +.dest: resd 1 +.skip: resd 1 +[section .text] +[global _decode0_BMP] +_decode0_BMP: + push ebx + push ebp + push esi + push edi + mov esi, [esp+decode.module] + mov eax, [esp+decode.size] + call bmpHeader + ;ret:eax=width, ecx=hegiht, edx=paletteSize, ebx=palette + ; ebp=bpp, esi=endOfImage, edi=successFlag + test edi,edi + jz .error + mov edi, [esp+decode.dest] + push dword[esp+decode.outputType] + push dword[esp+4+decode.skip] + push ecx ;height + push eax + push edx + mul ebp + add eax, byte 31 + shr eax, 3 + and al, -4 + push eax + mov edx, ebp + mov ebp, esp + call bmp2beta ;ecx!=0 for error + add esp, byte bb.size + mov eax, ecx + test ecx, ecx + jz .ret +.error: push byte 1 + pop eax +.ret: pop edi + pop esi + pop ebp + pop ebx + ret + +[absolute -4*2] +bb: +.col0: resd 1 ;bpp1ǻȤ +.reteip: resd 1 +.sw: resd 1 ;byte +.paletteSize: resd 1 ;byte +.w: resd 1 ;pixel +.h: resd 1 +.s: resd 1 +.t: resd 1 +.size: equ $-$$ +[section .text] +;eax=?, ecx=height, edx=bpp, ebx=palette +;ebp=bb, esi=endOfImage, edi=dest +bmp2beta: + mov al, [ebp+bb.t] + and al, 0x7f + cmp al, 2 + je near buf16 + cmp al, 4 + je buf32 + mov ecx, esp ;!=0 + ret +;=============================================================== +; Buffer mode 4 +;=============================================================== +buf32: + dec edx + je near .bpp1 + sub edx, byte 4-1 + je .bpp4 + sub edx, byte 8-4 + je .bpp8 + sub edx, byte 24-8 + je .bpp24 + mov ecx, esp ;!=0 + ret +;--------------------------------------------------- +; 24bpp BMP to 4byte bufer +;--------------------------------------------------- +.bpp24: + ;ecx=height, edx=0, ebx=palette + ;esi=endOfImage, edi=destinationBuffer + ;bb.w=width(pixel), bb.s=skipByte, bb.h=height + ;bb.t=outputType, bb.sw=sourceWidthByte + + .do24.1: + sub esi, [ebp+bb.sw] ;esi=startOfLine + push ecx + push esi + mov ecx, [ebp+bb.w] + .do24.2: + mov al, [esi] + mov [edi+3], dl + mov [edi], al + mov al, [esi+1] + mov [edi+1], al + mov al, [esi+2] + mov [edi+2], al + add esi, byte 3 + add edi, byte 4 + dec ecx + jnz .do24.2 + pop esi + pop ecx + add edi, [ebp+bb.s] + dec ecx + jnz .do24.1 + ret + +;--------------------------------------------------- +; 8bpp BMP to 4byte buffer +;--------------------------------------------------- +.bpp8: + ;ecx=height, edx=0, ebx=palette + ;esi=endOfImage, edi=destinationBuffer + + ;palleteѴ + mov dl, 255 + mov eax, [ebp+bb.paletteSize] + sub ebx, eax + shl eax, 8 + add ebx, eax ;ebx += paletteSize*255 + .do8.1: + mov eax, [ebx] + sub ebx, [ebp+bb.paletteSize] + and eax, 0x00ffffff + dec edx + push eax + jns .do8.1 + + .do8.2: + sub esi, [ebp+bb.sw] ;esi=firstLineStart + push ecx + push esi + mov ecx, [ebp+bb.w] + .do8.3: + xor eax, eax + add edi, byte 4 + mov al, [esi] + inc esi + ;AGI stole + mov eax, [esp+eax*4+8] + dec ecx + mov [edi-4], eax + jnz .do8.3 + pop esi + pop ecx + add edi, [ebp+bb.s] + dec ecx + jnz .do8.2 + add esp, 256*4 ;palette + ret + +;--------------------------------------------------- +; 4bpp BMP to 4byte buffer +;--------------------------------------------------- +.bpp4: + ;ecx=height, edx=0, ebx=palette + ;esi=endOfImage, edi=destinationBuffer + + ;palleteѴ + mov dl, 16 + mov eax, [ebp+bb.paletteSize] + sub ebx, eax + shl eax, 4 + add ebx, eax ;ebx+=eax*15 + .do4.1 + mov eax, [ebx] + sub ebx, [ebp+bb.paletteSize] + and eax, 0x00ffffff + dec edx + push eax + jnz .do4.1 + + .do4.2: + sub esi, [ebp+bb.sw] ;esi=firstLineStart + push ecx + push esi + mov ecx, [ebp+bb.w] + .do4.3: + xor edx, edx + mov al, [esi] + mov dl, al + inc esi + shr dl, 4 + and eax, byte 15 + add edi, byte 4 + dec ecx + mov edx, [esp+edx*4+8] + mov eax, [esp+eax*4+8] + mov [edi-4], edx + jz .wend + mov [edi], eax + add edi, byte 4 + dec ecx + jnz .do4.3 +.wend: pop esi + pop ecx + add edi, [ebp+bb.s] + dec ecx + jnz .do4.2 + add esp, 16*4 ;palette + ret + +;--------------------------------------------------- +; 1bpp BMP to 4byte buffer +;--------------------------------------------------- +.bpp1: + ;ecx=height, edx=0, ebx=palette + ;esi=endOfImage, edi=destinationBuffer + + ;palleteѴ + mov eax, [ebx] + add ebx, [ebp+bb.paletteSize] + and eax, 0x00ffffff + mov ebx, [ebx] + and ebx, 0x00ffffff + xor ebx, eax + ;push ebx + push eax + + .do1.1: + sub esi, [ebp+bb.sw] ;esi=firstLineStart + push ecx + push esi + mov ecx, [ebp+bb.w] + .do1.2: + mov dl, [esi] + inc esi + push esi + mov esi, 8 + .do1.3: + add edi, byte 4 + add dl, dl + sbb eax, eax + and eax, ebx + xor eax, [ebp+bb.col0] + dec ecx + mov [edi-4], eax + jz .wend1bpp + dec esi + jnz .do1.3 + pop esi + jmp short .do1.2 +.wend1bpp:pop ecx + pop esi + pop ecx + add edi, [ebp+bb.s] + dec ecx + jnz .do1.1 + pop eax + ret + +;=============================================== +; Buffer mode 2byte +;=============================================== +buf16: + dec edx + je near .bpp1 + sub edx, byte 4-1 + je near .bpp4 + sub edx, byte 8-4 + je .bpp8 + sub edx, byte 24-8 + je .bpp24 + mov ecx, esp + ret +;--------------------------------------------------- +; 24bpp BMP to 2byte bufer +;--------------------------------------------------- +.bpp24: + ;ecx=height, edx=0, ebx=palette + ;esi=endOfImage, edi=destinationBuffer + + .do24.1: + sub esi, [ebp+bb.sw] ;esi=startOfLine + push ecx + push esi + mov ecx, [ebp+bb.w] + .do24.2: + mov al, [esi+2] + shl eax, 16 + mov ax, [esi] + add esi, byte 3 + ; eax=24bitColor, edx=work, ecx=counter, ebx=work + ;礵μ̣פä롼äƤ褷( + ;Ȼ롼äƤ褷 + shr ah, 2 ;???????? RRRRRrrr 00GGGGGG BBBBBbbb + inc edi + shr eax, 3 ;000????? ???RRRRR rrr00GGG GGGBBBBB + shl ax, 5 ;000????? ???RRRRR GGGGGGBB BBB00000 + inc edi + shr eax, 5 ;00000000 ???????? RRRRRGGG GGGBBBBB + dec ecx + mov [edi-2], ax + jnz .do24.2 + pop esi + pop ecx + add edi, [ebp+bb.s] + dec ecx + jnz .do24.1 + ret + +;--------------------------------------------------- +; 8bpp BMP to 2byte buffer +;--------------------------------------------------- +.bpp8: + ;ecx=height, edx=0, ebx=palette + ;esi=endOfImage, edi=destinationBuffer + + ;palleteѴ + mov dl, 255 + mov eax, [ebp+bb.paletteSize] + sub ebx, eax + shl eax, 8 + add ebx, eax ;ebx += paletteSize*255 + .do8.1: + mov eax, [ebx] + sub ebx, [ebp+bb.paletteSize] + call .paletteConv + dec edx + push eax + jns .do8.1 + + .do8.2: + sub esi, [ebp+bb.sw] ;esi=firstLineStart + push ecx + push esi + mov ecx, [ebp+bb.w] + .do8.3: + xor eax, eax + add edi, byte 2 + mov al, [esi] + inc esi + ;AGI stole + mov eax, [esp+eax*4+8] + dec ecx + mov [edi-2], ax + jnz .do8.3 + pop esi + pop ecx + add edi, [ebp+bb.s] + dec ecx + jnz .do8.2 + add esp, 256*4 ;palette + ret + +;--------------------------------------------------- +; 4bpp BMP to 2byte buffer +;--------------------------------------------------- +.bpp4: + ;ecx=height, edx=0, ebx=palette + ;esi=endOfImage, edi=destinationBuffer + + ;palleteѴ + mov dl, 16 + mov eax, [ebp+bb.paletteSize] + sub ebx, eax + shl eax, 4 + add ebx, eax ;ebx+=eax*15 + .do4.1: + mov eax, [ebx] + sub ebx, [ebp+bb.paletteSize] + call .paletteConv + dec edx + push eax + jnz .do4.1 + + .do4.2: + sub esi, [ebp+bb.sw] ;esi=firstLineStart + push ecx + push esi + mov ecx, [ebp+bb.w] + .do4.3: + xor edx, edx + mov al, [esi] + mov dl, al + inc esi + shr dl, 4 + and eax, byte 15 + add edi, byte 2 + dec ecx + mov edx, [esp+edx*4+8] + mov eax, [esp+eax*4+8] + mov [edi-2], dx + jz .wend + mov [edi], ax + add edi, byte 2 + dec ecx + jnz .do4.3 +.wend: pop esi + pop ecx + add edi, [ebp+bb.s] + dec ecx + jnz .do4.2 + add esp, 16*4 ;palette + ret + +;--------------------------------------------------- +; 1bpp BMP to 2byte buffer +;--------------------------------------------------- +.bpp1: + ;ecx=height, edx=0, ebx=palette + ;esi=endOfImage, edi=destinationBuffer + + ;palleteѴ + mov eax, [ebx] + add ebx, [ebp+bb.paletteSize] + call .paletteConv + push eax + mov eax, [ebx] + call .paletteConv + pop ebx + xchg eax, ebx + xor ebx, eax + push eax + + .do1.1: + sub esi, [ebp+bb.sw] ;esi=firstLineStart + push ecx + push esi + mov ecx, [ebp+bb.w] + .do1.2: + mov dl, [esi] + inc esi + push esi + mov esi, 8 + .do1.3: + add dl, dl + inc edi + sbb eax, eax + inc edi + and eax, ebx + xor eax, [ebp+bb.col0] + dec ecx + mov [edi-2], ax + jz .wend1bpp + dec esi + jnz .do1.3 + pop esi + jmp short .do1.2 +.wend1bpp: + pop ecx + pop esi + pop ecx + add edi, [ebp+bb.s] + dec ecx + jnz .do1.1 + pop eax + ret + +.paletteConv: + shr ah, 2 + shr eax, 3 + shl ax, 5 + shr eax, 5 + ret diff --git a/30_day/gview/bmp.obj b/30_day/gview/bmp.obj new file mode 100644 index 0000000000000000000000000000000000000000..335ca9d41246f2d6b566a74014e9c88dd0be881f GIT binary patch literal 4292 zcmZ{me{54#6vtnGFb3k@BtQnD4pS6FpL8QI1VJ~}GId)SKQ?}j*1nG7*4FkF{DBI# zL%RASivReBCML!N|IuKC#6;531yLh0i$SA8ApCGlMPs7OWHP_!zT0=-6?jS4b3XTb z&pqed+xzyI!=cRj;MwKXZbdN^^U)0bsgh0Pyh~A*;+r(3r&_7px_a%p_PpV#&ad#y z9ID1h@0gms1>b;GIbV6MWm0ZgYwmfsKR433W%I`3D^tq6V{P8S%*bSQ?=%P_dzRHV ztJ#?_GnaQ~3cEK3*x1X~SnnQ+*HV%BXOh}`8|g-7sC&C%yt1jHLOtx8tR8Neq8^S_ z9d!LNFEg@G-P_6sGneM5z4dUGwA`-tE{2i!P0qJWgLvjaw`<45w!oDOnZo$~Ay@8b zrr`37&OO?8F~`XzhNrwkeF=ptb5Hs=WCq+tUhPa&TQyWOHa14p&ZnrmJf1PM z0iSzU1==X)9f;`}4djM%7lx)nk{PJV9q;`@%~HVajt_wV0>{7G6%)l6>pBb*SMDx}`+Salen+3rxzF#+9CKwp zcQ>WaZ&~kpuCgipZSmk(zR^9m*ng(nQOvvMZFbK_`pP4Lr~fR4@fI+pugsTUku7h^ z`A5^2`Q+1k1{7?2@n9tn;g&Jj?4O z4}B~%@DS2*@pSUH?m0(kd5eKkR(;ca>yFS&%u@!Z7iN85+c-k$so65nmh{hCe)(}d z5BFsUb?$dkQ|IUiWroqY<;=KF=X}ooGnJ8i8TwWD)#=BUMf%T-!}qwRNX~yXeVPY8 zac%#GzC+Oe_s?1CADjIfpMB~^4IJ9fV%)HSPOE{DT>DiuI|1?twa|$z<-rH677jIH zIFNS@J&5m(`>)qTWzavp;5U0nDc+!o=ml>DI#JXj(QX|f>A5=*EyAEf`A0yVLAi!6qv%rM@{}NlZd+>537g0@R6*AXV@tN@O-X(h1G| z@Fq*-0eE!h2#pWk42iVCqsvHWw!*tzB2U7*QzEu5DQ1^xA zZV=JKhE?fc7~}Mq8b-9xHKa?yL`jqUUlp|w&}lH^;M7H9k+>}mnad~$9+A(ZAe9o? z03z2F0gHHbV=ZkF7|LtV&?8oV3xw_~LEZzIB$1E!Ec&8-Q}>#Iqk?i{P47 z5P2Wu0gHq}#1v%&uNZT!P)K_`-aX$&X#6l{joLM-orLj-4Ev$6oy?HNBx2tYc^l0T z`wo&KB02_w9kq9iG`Ik49mAQg3F$^~xu_x?siiBS-69m@8|1S~B0pV2E`ekv&EFsg zB;vr~`$Qr)gA^q)9po#C%m(>YBJ)8;B(fBw4C?{%6TT9pLLzHG>Lk($vO*%;LDoxT z2S`vNFM@2B$g3c9V$9V;>4=wZ+1D*XJ$xIQLlQY~4LJmIMA8&NsI#K36Ci&{mSh4ydkar}~0P?;>T0uUP z$VQN_B(fdkq(yeY!#hlita&=2o7QSN&5X51BK1)t#hj>xqwUeKvCV`l^=Q{N!?Xk4 z!I;j)nAQ+a$M{G?yeE;=Q>kb?CSo=91iQ?2q8))ivpKNdvKqRRYg2mI#BiE=67i%F zG(+MAD>7zIDLdxa@+RL(ojF$a%o7DLSJc2

    GyQ$xxyMzR=Bd_b{buLbR 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