From 1b8b0c62297db3371e038e4d4810473d7ffc7f6e Mon Sep 17 00:00:00 2001 From: Paul Chaignon Date: Sun, 28 Jun 2015 13:24:42 +0200 Subject: [PATCH] New .inc Assembly samples --- samples/Assembly/lib.inc | 170 +++++++++++++++++++ samples/Assembly/macros.inc | 321 ++++++++++++++++++++++++++++++++++++ 2 files changed, 491 insertions(+) create mode 100644 samples/Assembly/lib.inc create mode 100644 samples/Assembly/macros.inc diff --git a/samples/Assembly/lib.inc b/samples/Assembly/lib.inc new file mode 100644 index 00000000..1faceead --- /dev/null +++ b/samples/Assembly/lib.inc @@ -0,0 +1,170 @@ + +; ------------------------------------------------------------------------ +; 显示 AL 中的数字 +; ------------------------------------------------------------------------ +DispAL: + push ecx + push edx + push edi + + mov edi, [dwDispPos] + + mov ah, 0Fh ; 0000b: 黑底 1111b: 白字 + mov dl, al + shr al, 4 + mov ecx, 2 +.begin: + and al, 01111b + cmp al, 9 + ja .1 + add al, '0' + jmp .2 +.1: + sub al, 0Ah + add al, 'A' +.2: + mov [gs:edi], ax + add edi, 2 + + mov al, dl + loop .begin + ;add edi, 2 + + mov [dwDispPos], edi + + pop edi + pop edx + pop ecx + + ret +; DispAL 结束------------------------------------------------------------- + + +; ------------------------------------------------------------------------ +; 显示一个整形数 +; ------------------------------------------------------------------------ +DispInt: + mov eax, [esp + 4] + shr eax, 24 + call DispAL + + mov eax, [esp + 4] + shr eax, 16 + call DispAL + + mov eax, [esp + 4] + shr eax, 8 + call DispAL + + mov eax, [esp + 4] + call DispAL + + mov ah, 07h ; 0000b: 黑底 0111b: 灰字 + mov al, 'h' + push edi + mov edi, [dwDispPos] + mov [gs:edi], ax + add edi, 4 + mov [dwDispPos], edi + pop edi + + ret +; DispInt 结束------------------------------------------------------------ + +; ------------------------------------------------------------------------ +; 显示一个字符串 +; ------------------------------------------------------------------------ +DispStr: + push ebp + mov ebp, esp + push ebx + push esi + push edi + + mov esi, [ebp + 8] ; pszInfo + mov edi, [dwDispPos] + mov ah, 0Fh +.1: + lodsb + test al, al + jz .2 + cmp al, 0Ah ; 是回车吗? + jnz .3 + push eax + mov eax, edi + mov bl, 160 + div bl + and eax, 0FFh + inc eax + mov bl, 160 + mul bl + mov edi, eax + pop eax + jmp .1 +.3: + mov [gs:edi], ax + add edi, 2 + jmp .1 + +.2: + mov [dwDispPos], edi + + pop edi + pop esi + pop ebx + pop ebp + ret +; DispStr 结束------------------------------------------------------------ + +; ------------------------------------------------------------------------ +; 换行 +; ------------------------------------------------------------------------ +DispReturn: + push szReturn + call DispStr ;printf("\n"); + add esp, 4 + + ret +; DispReturn 结束--------------------------------------------------------- + + +; ------------------------------------------------------------------------ +; 内存拷贝,仿 memcpy +; ------------------------------------------------------------------------ +; void* MemCpy(void* es:pDest, void* ds:pSrc, int iSize); +; ------------------------------------------------------------------------ +MemCpy: + push ebp + mov ebp, esp + + push esi + push edi + push ecx + + mov edi, [ebp + 8] ; Destination + mov esi, [ebp + 12] ; Source + mov ecx, [ebp + 16] ; Counter +.1: + cmp ecx, 0 ; 判断计数器 + jz .2 ; 计数器为零时跳出 + + mov al, [ds:esi] ; ┓ + inc esi ; ┃ + ; ┣ 逐字节移动 + mov byte [es:edi], al ; ┃ + inc edi ; ┛ + + dec ecx ; 计数器减一 + jmp .1 ; 循环 +.2: + mov eax, [ebp + 8] ; 返回值 + + pop ecx + pop edi + pop esi + mov esp, ebp + pop ebp + + ret ; 函数结束,返回 +; MemCpy 结束------------------------------------------------------------- + diff --git a/samples/Assembly/macros.inc b/samples/Assembly/macros.inc new file mode 100644 index 00000000..dc968ad9 --- /dev/null +++ b/samples/Assembly/macros.inc @@ -0,0 +1,321 @@ +BLARGG_MACROS_INCLUDED = 1 + +; Allows extra error checking with modified version +; of ca65. Otherwise acts like a constant of 0. +ADDR = 0 + +; Switches to Segment and places Line there. +; Line can be an .align directive, .res, .byte, etc. +; Examples: +; seg_data BSS, .align 256 +; seg_data RODATA, {message: .byte "Test",0} +.macro seg_data Segment, Line + .pushseg + .segment .string(Segment) + Line + .popseg +.endmacro + +; Reserves Size bytes in Segment for Name. +; If Size is omitted, reserves one byte. +.macro seg_res Segment, Name, Size + .ifblank Size + seg_data Segment, Name: .res 1 + .else + seg_data Segment, Name: .res Size + .endif +.endmacro + +; Shortcuts for zeropage, bss, and stack +.define zp_res seg_res ZEROPAGE, +.define nv_res seg_res NVRAM, +.define bss_res seg_res BSS, +.define sp_res seg_res STACK, +.define zp_byte zp_res + +; Copies byte from Src to Addr. If Src begins with #, +; it sets Addr to the immediate value. +; Out: A = byte copied +; Preserved: X, Y +.macro mov Addr, Src + lda Src + sta Addr +.endmacro + +; Copies word from Src to Addr. If Src begins with #, +; it sets Addr the immediate value. +; Out: A = high byte of word +; Preserved: X, Y +.macro movw Addr, Src + .if .match( .left( 1, {Src} ), # ) + lda #<(.right( .tcount( {Src} )-1, {Src} )) + sta Addr + lda #>(.right( .tcount( {Src} )-1, {Src} )) + sta 1+(Addr) + .else + lda Src + sta Addr + lda 1+(Src) + sta 1+(Addr) + .endif +.endmacro + +; Increments 16-bit value at Addr. +; Out: EQ/NE based on resulting 16-bit value +; Preserved: A, X, Y +.macro incw Addr + .local @Skip + inc Addr + bne @Skip + inc 1+(Addr) +@Skip: +.endmacro + +; Adds Src to word at Addr. +; Out: A = high byte of result, carry set appropriately +; Preserved: X, Y +.macro addw Addr, Src + .if .match( .left( 1, {Src} ), # ) + addw_ Addr,(.right( .tcount( {Src} )-1, {Src} )) + .else + lda Addr + clc + adc Src + sta Addr + + lda 1+(Addr) + adc 1+(Src) + sta 1+(Addr) + .endif +.endmacro +.macro addw_ Addr, Imm + lda Addr + clc + adc #> 8) <> 0 + lda 1+(Addr) + adc #>Imm + sta 1+(Addr) + ;.else + ; .local @Skip + ; bcc @Skip + ; inc 1+(Addr) + ;@Skip: + ;.endif +.endmacro + +; Splits list of words into tables of low and high bytes +; Example: split_words foo, {$1234, $5678} +; expands to: +; foo_l: $34, $78 +; foo_h: $12, $56 +; foo_count = 2 +.macro split_words Label, Words + .ident (.concat (.string(Label), "_l")): .lobytes Words + .ident (.concat (.string(Label), "_h")): .hibytes Words + .ident (.concat (.string(Label), "_count")) = * - .ident (.concat (.string(Label), "_h")) +.endmacro + +.macro SELECT Bool, True, False, Extra + .ifndef Bool + False Extra + .elseif Bool <> 0 + True Extra + .else + False Extra + .endif +.endmacro + +.macro DEFAULT Name, Value + .ifndef Name + Name = Value + .endif +.endmacro + +.ifp02 + ; 6502 doesn't define these alternate names + .define blt bcc + .define bge bcs +.endif +.define jlt jcc +.define jge jcs + +; Jxx Target = Bxx Target, except it can go farther than +; 128 bytes. Implemented via branch around a JMP. + +; Don't use ca65's longbranch, because they fail for @labels +;.macpack longbranch + +.macro jeq Target + bne *+5 + jmp Target +.endmacro + +.macro jne Target + beq *+5 + jmp Target +.endmacro + +.macro jmi Target + bpl *+5 + jmp Target +.endmacro + +.macro jpl Target + bmi *+5 + jmp Target +.endmacro + +.macro jcs Target + bcc *+5 + jmp Target +.endmacro + +.macro jcc Target + bcs *+5 + jmp Target +.endmacro + +.macro jvs Target + bvc *+5 + jmp Target +.endmacro + +.macro jvc Target + bvs *+5 + jmp Target +.endmacro + + +; Passes constant data to routine in addr +; Preserved: A, X, Y +.macro jsr_with_addr routine,data + .local Addr + pha + lda #Addr + sta addr+1 + pla + jsr routine + seg_data RODATA,{Addr: data} +.endmacro + +; Calls routine multiple times, with A having the +; value 'start' the first time, 'start+step' the +; second time, up to 'end' for the last time. +.macro for_loop routine,start,end,step + .local @for_loop + lda #start +@for_loop: + pha + jsr routine + pla + clc + adc #step + cmp #<((end)+(step)) + bne @for_loop +.endmacro + +; Calls routine n times. The value of A in the routine +; counts from 0 to n-1. +.macro loop_n_times routine,n + for_loop routine,0,n-1,+1 +.endmacro + +; Same as for_loop, except uses 16-bit value in YX. +; -256 <= step <= 255 +.macro for_loop16 routine,start,end,step +.if (step) < -256 || (step) > 255 + .error "Step must be within -256 to 255" +.endif + .local @for_loop_skip + .local @for_loop + ldy #>(start) + lda #<(start) +@for_loop: + tax + pha + tya + pha + jsr routine + pla + tay + pla + clc + adc #step +.if (step) > 0 + bcc @for_loop_skip + iny +.else + bcs @for_loop_skip + dey +.endif +@for_loop_skip: + cmp #<((end)+(step)) + bne @for_loop + cpy #>((end)+(step)) + bne @for_loop +.endmacro + +; Stores byte at addr +; Preserved: X, Y +.macro setb addr, byte + lda #byte + sta addr +.endmacro + +; Stores word at addr +; Preserved: X, Y +.macro setw addr, word + lda #<(word) + sta addr + lda #>(word) + sta addr+1 +.endmacro + +; Loads XY with 16-bit immediate or value at address +.macro ldxy Arg + .if .match( .left( 1, {Arg} ), # ) + ldy #<(.right( .tcount( {Arg} )-1, {Arg} )) + ldx #>(.right( .tcount( {Arg} )-1, {Arg} )) + .else + ldy (Arg) + ldx (Arg)+1 + .endif +.endmacro + +; Increments XY as 16-bit register, in CONSTANT time. +; Z flag set based on entire result. +; Preserved: A +; Time: 7 clocks +.macro inxy + iny ; 2 + beq *+4 ; 3 + ; -1 + bne *+3 ; 3 + ; -1 + inx ; 2 +.endmacro + +; Negates A and adds it to operand +.macro subaf Operand + eor #$FF + sec + adc Operand +.endmacro + +; Initializes CPU registers to reasonable values +; Preserved: A, Y +.macro init_cpu_regs + sei + cld ; unnecessary on NES, but might help on clone + ldx #$FF + txs + .ifndef BUILD_NSF + inx + stx PPUCTRL + .endif +.endmacro