| /* |
| * Minimal Alpha system boot code. |
| * |
| * Copyright Linaro Ltd 2019 |
| */ |
| |
| .set noat |
| .set nomacro |
| .arch ev6 |
| .text |
| |
| .macro load_pci_io reg |
| /* For typhoon, this is |
| * 0xfffffc0000000000 -- kseg identity map |
| * + 0x10000000000 -- typhoon pio base |
| * + 0x1fc000000 -- typhoon pchip0 pci base |
| * = 0xfffffd01fc000000 |
| */ |
| ldah \reg, -3 /* ff..fd0000 */ |
| lda \reg, 0x1fc(\reg) /* ff..fd01fc */ |
| sll \reg, 24, \reg |
| .endm |
| |
| #define com1Rbr 0x3f8 |
| #define com1Thr 0x3f8 |
| #define com1Ier 0x3f9 |
| #define com1Iir 0x3fa |
| #define com1Lcr 0x3fb |
| #define com1Mcr 0x3fc |
| #define com1Lsr 0x3fd |
| #define com1Msr 0x3fe |
| #define com1Scr 0x3ff |
| #define com1Dll 0x3f8 |
| #define com1Dlm 0x3f9 |
| |
| #define PAL_halt 0 |
| #define PAL_wrent 52 |
| #define PAL_wrkgp 55 |
| |
| .text |
| .p2align 4 |
| .globl _start |
| .ent _start |
| _start: |
| br $gp, .+4 |
| ldah $gp, 0($gp) !gpdisp!1 |
| lda $gp, 0($gp) !gpdisp!1 |
| |
| ldah $sp, $stack_end($gp) !gprelhigh |
| lda $sp, $stack_end($sp) !gprellow |
| |
| /* Install kernel gp for exception handlers. */ |
| mov $gp, $16 |
| call_pal PAL_wrkgp |
| |
| /* Install exception handlers. */ |
| ldah $16, entInt($gp) !gprelhigh |
| lda $16, entInt($16) !gprellow |
| lda $17, 0 |
| call_pal PAL_wrent |
| |
| ldah $16, entArith($gp) !gprelhigh |
| lda $16, entArith($16) !gprellow |
| lda $17, 1 |
| call_pal PAL_wrent |
| |
| ldah $16, entMM($gp) !gprelhigh |
| lda $16, entMM($16) !gprellow |
| lda $17, 2 |
| call_pal PAL_wrent |
| |
| ldah $16, entIF($gp) !gprelhigh |
| lda $16, entIF($16) !gprellow |
| lda $17, 3 |
| call_pal PAL_wrent |
| |
| ldah $16, entUna($gp) !gprelhigh |
| lda $16, entUna($16) !gprellow |
| lda $17, 4 |
| call_pal PAL_wrent |
| |
| ldah $16, entSys($gp) !gprelhigh |
| lda $16, entSys($16) !gprellow |
| lda $17, 5 |
| call_pal PAL_wrent |
| |
| /* |
| * Initialize COM1. |
| */ |
| load_pci_io $1 |
| lda $2, 0x87 /* outb(0x87, com1Lcr); */ |
| stb $2, com1Lcr($1) |
| stb $31, com1Dlm($1) /* outb(0, com1Dlm); */ |
| lda $2, 3 /* baudconst 3 => 56000 */ |
| stb $2, com1Dll($1) /* outb(baudconst, com1Dll); */ |
| lda $2, 0x07 |
| stb $2, com1Lcr($1) /* outb(0x07, com1Lcr) */ |
| lda $2, 0x0f |
| stb $2, com1Mcr($1) /* outb(0x0f, com1Mcr) */ |
| |
| bsr $26, main !samegp |
| |
| /* fall through to _exit */ |
| .end _start |
| |
| .globl _exit |
| .ent _exit |
| _exit: |
| .frame $sp, 0, $26, 0 |
| .prologue 0 |
| |
| /* We cannot return an error code. */ |
| call_pal PAL_halt |
| .end _exit |
| |
| /* |
| * We have received an exception that we don't handle. Log and exit. |
| */ |
| .ent log_exit |
| log_exit: |
| entInt: |
| entArith: |
| entMM: |
| entIF: |
| entUna: |
| entSys: |
| ldah $16, $errormsg($gp) !gprelhigh |
| lda $16, $errormsg($16) !gprellow |
| bsr $26, __sys_outs !samegp |
| bsr $26, _exit !samegp |
| .end log_exit |
| |
| .section .rodata |
| $errormsg: |
| .string "Terminated by exception.\n" |
| .previous |
| |
| /* |
| * Helper Functions |
| */ |
| |
| /* Output a single character to serial port */ |
| .global __sys_outc |
| .ent __sys_outc |
| __sys_outc: |
| .frame $sp, 0, $26, 0 |
| .prologue 0 |
| |
| load_pci_io $1 |
| |
| /* |
| * while ((inb(com1Lsr) & 0x20) == 0) |
| * continue; |
| */ |
| 1: ldbu $0, com1Lsr($1) |
| and $0, 0x20, $0 |
| beq $0, 1b |
| |
| /* outb(c, com1Thr); */ |
| stb $16, com1Thr($1) |
| ret |
| .end __sys_outc |
| |
| /* Output a nul-terminated string to serial port */ |
| .global __sys_outs |
| .ent __sys_outs |
| __sys_outs: |
| .frame $sp, 0, $26, 0 |
| .prologue 0 |
| |
| load_pci_io $1 |
| |
| ldbu $2, 0($16) |
| beq $2, 9f |
| |
| /* |
| * while ((inb(com1Lsr) & 0x20) == 0) |
| * continue; |
| */ |
| 1: ldbu $0, com1Lsr($1) |
| and $0, 0x20, $0 |
| beq $0, 1b |
| |
| /* outb(c, com1Thr); */ |
| stb $2, com1Thr($1) |
| |
| addq $16, 1, $16 |
| ldbu $2, 0($16) |
| bne $2, 1b |
| |
| 9: ret |
| .end __sys_outs |
| |
| /* |
| * Division routines that are normally in libc. |
| * |
| * These do not follow the C calling convention. Arguments are in $24+$25, |
| * the result is in $27. Register $28 may be clobbered; everything else |
| * must be saved. |
| * |
| * We store the remainder in $28, so that we can share code. |
| * |
| * We do not signal divide by zero. |
| */ |
| |
| /* |
| * Unsigned 64-bit division. |
| */ |
| |
| .globl __divqu |
| .ent __divqu |
| __divqu: |
| .frame $sp, 48, $23 |
| subq $sp, 48, $sp |
| stq $0, 0($sp) |
| stq $1, 8($sp) |
| stq $2, 16($sp) |
| stq $3, 24($sp) |
| stq $4, 32($sp) |
| .prologue 0 |
| |
| #define mask $0 |
| #define divisor $1 |
| #define compare $2 |
| #define tmp1 $3 |
| #define tmp2 $4 |
| #define quotient $27 |
| #define modulus $28 |
| |
| mov $24, modulus |
| mov $25, divisor |
| mov $31, quotient |
| mov 1, mask |
| beq $25, 9f |
| |
| /* Shift left until divisor >= modulus. */ |
| 1: cmpult divisor, modulus, compare |
| blt divisor, 2f |
| addq divisor, divisor, divisor |
| addq mask, mask, mask |
| bne compare, 1b |
| |
| 2: addq quotient, mask, tmp2 |
| srl mask, 1, mask |
| cmpule divisor, modulus, compare |
| subq modulus, divisor, tmp1 |
| cmovne compare, tmp2, quotient |
| srl divisor, 1, divisor |
| cmovne compare, tmp1, modulus |
| bne mask, 2b |
| |
| 9: ldq $0, 0($sp) |
| ldq $1, 8($sp) |
| ldq $2, 16($sp) |
| ldq $3, 24($sp) |
| ldq $4, 32($sp) |
| addq $sp, 48, $sp |
| ret $31, ($23), 1 |
| |
| #undef mask |
| #undef divisor |
| #undef compare |
| #undef tmp1 |
| #undef tmp2 |
| #undef quotient |
| #undef modulus |
| |
| .end __divqu |
| |
| /* |
| * Unsigned 64-bit remainder. |
| * Note that __divqu above leaves the result in $28. |
| */ |
| |
| .globl __remqu |
| .ent __remqu |
| __remqu: |
| .frame $sp, 16, $23 |
| subq $sp, 16, $sp |
| stq $23, 0($sp) |
| .prologue 0 |
| |
| bsr $23, __divqu |
| |
| ldq $23, 0($sp) |
| mov $28, $27 |
| addq $sp, 16, $sp |
| ret $31, ($23), 1 |
| .end __remqu |
| |
| /* |
| * Signed 64-bit division. |
| */ |
| |
| .globl __divqs |
| .ent __divqs |
| __divqs: |
| .prologue 0 |
| |
| /* Common case: both arguments are positive. */ |
| bis $24, $25, $28 |
| bge $28, __divqu |
| |
| /* At least one argument is negative. */ |
| subq $sp, 32, $sp |
| stq $23, 0($sp) |
| stq $24, 8($sp) |
| stq $25, 16($sp) |
| |
| /* Compute absolute values. */ |
| subq $31, $24, $28 |
| cmovlt $24, $28, $24 |
| subq $31, $25, $28 |
| cmovlt $25, $28, $25 |
| |
| bsr $23, __divqu |
| |
| ldq $24, 8($sp) |
| ldq $25, 16($sp) |
| |
| /* -a / b = a / -b = -(a / b) */ |
| subq $31, $27, $23 |
| xor $24, $25, $28 |
| cmovlt $28, $23, $27 |
| |
| ldq $23, 0($sp) |
| addq $sp, 32, $sp |
| ret $31, ($23), 1 |
| .end __divqs |
| |
| /* |
| * Signed 64-bit remainder. |
| */ |
| |
| .globl __remqs |
| .ent __remqs |
| __remqs: |
| .prologue 0 |
| |
| /* Common case: both arguments are positive. */ |
| bis $24, $25, $28 |
| bge $28, __remqu |
| |
| /* At least one argument is negative. */ |
| subq $sp, 32, $sp |
| stq $23, 0($sp) |
| stq $24, 8($sp) |
| stq $25, 16($sp) |
| |
| /* Compute absolute values. */ |
| subq $31, $24, $28 |
| cmovlt $24, $28, $24 |
| subq $31, $25, $28 |
| cmovlt $25, $28, $25 |
| |
| bsr $23, __divqu |
| |
| ldq $23, 0($sp) |
| ldq $24, 8($sp) |
| ldq $25, 16($sp) |
| |
| /* -a % b = -(a % b); a % -b = a % b. */ |
| subq $31, $28, $27 |
| cmovge $24, $28, $27 |
| |
| addq $sp, 32, $sp |
| ret $31, ($23), 1 |
| .end __remqs |
| |
| /* |
| * Unsigned 32-bit division. |
| */ |
| |
| .globl __divlu |
| .ent __divlu |
| __divlu: |
| .frame $sp, 32, $23 |
| subq $sp, 32, $sp |
| stq $23, 0($sp) |
| stq $24, 8($sp) |
| stq $25, 16($sp) |
| .prologue 0 |
| |
| /* Zero extend and use the 64-bit routine. */ |
| zap $24, 0xf0, $24 |
| zap $25, 0xf0, $25 |
| bsr $23, __divqu |
| |
| addl $27, 0, $27 |
| ldq $23, 0($sp) |
| ldq $24, 8($sp) |
| ldq $25, 16($sp) |
| addq $sp, 32, $sp |
| ret $31, ($23), 1 |
| .end __divlu |
| |
| /* |
| * Unsigned 32-bit remainder. |
| */ |
| |
| .globl __remlu |
| .ent __remlu |
| __remlu: |
| .frame $sp, 32, $23 |
| subq $sp, 32, $sp |
| stq $23, 0($sp) |
| stq $24, 8($sp) |
| stq $25, 16($sp) |
| .prologue 0 |
| |
| /* Zero extend and use the 64-bit routine. */ |
| zap $24, 0xf0, $24 |
| zap $25, 0xf0, $25 |
| bsr $23, __divqu |
| |
| /* Recall that the remainder is returned in $28. */ |
| addl $28, 0, $27 |
| ldq $23, 0($sp) |
| ldq $24, 8($sp) |
| ldq $25, 16($sp) |
| addq $sp, 32, $sp |
| ret $31, ($23), 1 |
| .end __remlu |
| |
| /* |
| * Signed 32-bit division. |
| */ |
| |
| .globl __divls |
| .ent __divls |
| __divls: |
| .frame $sp, 32, $23 |
| subq $sp, 32, $sp |
| stq $23, 0($sp) |
| stq $24, 8($sp) |
| stq $25, 16($sp) |
| .prologue 0 |
| |
| /* Sign extend. */ |
| addl $24, 0, $24 |
| addl $25, 0, $25 |
| |
| /* Compute absolute values. */ |
| subq $31, $24, $28 |
| cmovlt $24, $28, $24 |
| subq $31, $25, $28 |
| cmovlt $25, $28, $25 |
| |
| bsr $23, __divqu |
| |
| ldq $24, 8($sp) |
| ldq $25, 16($sp) |
| |
| /* Negate the unsigned result, if necessary. */ |
| xor $24, $25, $28 |
| subl $31, $27, $23 |
| addl $27, 0, $27 |
| addl $28, 0, $28 |
| cmovlt $28, $23, $27 |
| |
| ldq $23, 0($sp) |
| addq $sp, 32, $sp |
| ret $31, ($23), 1 |
| .end __divls |
| |
| /* |
| * Signed 32-bit remainder. |
| */ |
| |
| .globl __remls |
| .ent __remls |
| __remls: |
| .frame $sp, 32, $23 |
| subq $sp, 32, $sp |
| stq $23, 0($sp) |
| stq $24, 8($sp) |
| stq $25, 16($sp) |
| .prologue 0 |
| |
| /* Sign extend. */ |
| addl $24, 0, $24 |
| addl $25, 0, $25 |
| |
| /* Compute absolute values. */ |
| subq $31, $24, $28 |
| cmovlt $24, $28, $24 |
| subq $31, $25, $28 |
| cmovlt $25, $28, $25 |
| |
| bsr $23, __divqu |
| |
| ldq $23, 0($sp) |
| ldq $24, 8($sp) |
| ldq $25, 16($sp) |
| |
| /* Negate the unsigned result, if necessary. */ |
| subl $31, $28, $27 |
| addl $28, 0, $28 |
| cmovge $24, $28, $27 |
| |
| addq $sp, 32, $sp |
| ret $31, ($23), 1 |
| .end __remls |
| |
| .data |
| .p2align 4 |
| stack: |
| .skip 65536 |
| $stack_end: |
| .type stack,@object |
| .size stack, . - stack |