|
|
Darwin 0.1 Mach+BSD kernel
/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights * Reserved. This file contains Original Code and/or Modifications of * Original Code as defined in and that are subject to the Apple Public * Source License Version 1.1 (the "License"). You may not use this file * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource and read it before using * this file. * * The Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ .file "status.s" .ident "@(#)kern-fp:status.s 1.1" //$tt(*80387 emulator + + + s t a t u s + + + *) // ************************************************************************ // // s t a t u s . m o d // =================== // // ================================================================ // intel corporation proprietary information // this software is supplied under the terms of a license // agreement or non-disclosure agreement with intel corporation // and may not be copied nor disclosed except in accordance with // the terms of that agreement. // ================================================================= // // function: // operation cluster for 80387 status register // // public procedures: // stcw stenv pop_free // incr_top decr_top save_status // restore_status clear_p_error init // clex stsw ldcw // get_precision store_precision get_rnd_control // store_rnd_control u_masked? z_masked? // d_masked? i_masked? o_masked? // get_reg_tag affine_infinity? get_top // set_p_error p_error? set_u_error // set_o_error set_z_error set_i_error // i_error? d_error? set_d_error // set_z_bit clear_z_bit set_s_bit // clear_s_bit set_a_bit clear_a_bits // set_c_bit clear_c_bit store_reg_tag // set_i_masked? set_d_masked? set_z_masked? // clear_cond_bits // // ************************************************************************ // //...March 3, 1987... // .data //a_msr segment rw public // //...define the 80387 status register... // //%gs:sr_masks: .byte 0x07f / bit 6 on for d-step 8087 05/21/81 //%gs:sr_controls: .byte 0x13 //%gs:sr_reserved1: .value 0 / reserveds take care of 386 env //%gs:sr_errors: .byte 0 //%gs:sr_flags: .byte 0 / bit 2 off for sim286 09/14/83 //%gs:sr_reserved2: .value 0 //%gs:sr_tags: .value 0x0ffff //%gs:sr_reserved3: .value 0 //%gs:sr_instr_offset: .long 0 //%gs:sr_instr_base: .value 0 //%gs:sr_reserved4: .value 0 //%gs:sr_mem_offset: .long 0 //%gs:sr_mem_base: .value 0 //%gs:sr_reserved5: .value 0 //%gs:sr_regstack: .value 40 dup(0) //#define a_m%gs:sr_data %gs:sr_masks //a_msr ends // assume %ds:a_msr //$nolist #include "fp_e80387.h" //$list // // .globl %gs:sr_mem_offset // .globl %gs:sr_controls // .globl %gs:sr_mem_base // .globl a_m%gs:sr_data // .globl %gs:sr_regstack // .globl %gs:sr_flags // .globl %gs:sr_masks // .globl %gs:sr_errors // .globl %gs:sr_instr_offset // .globl %gs:sr_instr_base .globl incr_top .globl decr_top .globl save_status .globl pop_free .globl ldcw .globl stenv .globl clex .globl stsw .globl stcw .globl get_precision .globl store_precision .globl get_rnd_control .globl store_rnd_control .globl u_masked_ .globl d_masked_ .globl get_top .globl i_masked_ .globl o_masked_ .globl get_reg_tag .globl affine_infinity_ .globl set_p_error .globl set_u_error .globl set_o_error .globl init .globl clear_p_error .globl set_i_error .globl set_d_error .globl i_error_ .globl d_error_ .globl p_error_ .globl set_z_bit .globl clear_z_bit .globl set_s_bit .globl clear_s_bit .globl set_a_bit .globl clear_cond_bits .globl set_c_bit .globl clear_c_bit .globl store_reg_tag .globl set_i_masked_ .globl set_d_masked_ .globl set_z_masked_ .globl clear_a_bit .globl restore_status .globl set_stk_u_error .globl set_stk_o_error .globl correct_tag_word .globl free_reg // .text //a_med segment er public // --------to be added for unix //.. extrn fpfulong:far,fpfushort:far,fpsulong:far,fpsushort:far // // ************************************************************************* // // the routines in this section manipulate the status and control // information stored in the 80387 status data segment, a?msr. // // ************************************************************************ // transfer field group: get_precision, store_precision, get_rnd_control // store_rnd_control, get_top, get_reg_tag, store_reg_tag // // inputs: the *get* routines require no input parameters, except for the // procedures get_reg_tag and store_reg_tag which expect the // register number to be in al and cl, respectively // the *store* routines input the value to be stored in al. // // outputs: get_precison returns the 2-bit precision field in dl. // all other routines return justified values in al. // ************************************************************************ ALIGN get_precision: //proc movb $precision_mask,%dl // load precision field mask andb %gs:sr_controls,%dl // mask in precision control ret //get_precision endp // ALIGN store_precision: //proc andb $~precision_mask,%gs:sr_controls // clear precision orb %al,%gs:sr_controls // store new precision control ret //store_precision endp // ALIGN get_rnd_control: //proc movb %gs:sr_controls,%al // load control byte andb $rnd_control_mask,%al // mask in rounding control ret //get_rnd_control endp // ALIGN store_rnd_control: //proc andb $~rnd_control_mask,%gs:sr_controls // clear old field orb %al,%gs:sr_controls // store new rounding control ret //store_rnd_control endp // ALIGN get_top: //proc movb %gs:sr_flags,%al // load status flag byte andb $top_mask,%al // mask in top field shrb $3,%al // right justify top field ret //get_top endp // ALIGN get_reg_tag: //proc movzbl %al,%eax // form word bit count mov %eax,%ecx // store in cx shl $1,%ecx // bit count = 2 * reg num mov %ecx,%ebx // else, must examine register shl $2,%ebx // form index to %gs:sr_regstack add %ecx,%ebx // index = 10 * register num add $sr_regstack,%ebx // + start of %gs:sr_regstack movw %gs:sr_tags,%ax // load tag word shrw %cl,%ax // shift to tag of interest andb $empty,%al // mask out other tags cmpb inv,%al // if tag not = 2, jne got_tag // no further decoding needed movw %gs:8(%ebx),%ax // load register exponent andw $0x7fff,%ax // mask off sign bit jnz check_unsupp // if expon /= 0, check unsupported format movb denormd,%al // if exponent zero, denormal ret ALIGN check_unsupp: mov %gs:4(%ebx),%eax // get top 32 bits of significand test $0x080000000,%eax // is highest bit set. jnz check_nan // if so, check for nan movb unsupp,%al // if not, its an unsupported format. ret ALIGN check_nan: and $0x07fffffff,%eax // zero out most significant bit or %gs:(%ebx),%eax // or bottom 32 bits into top 32 bits. movb infinty,%al // tentatively set tag to infinitys jz got_tag // if fraction is 0, its infinity movb inv,%al // fraction is non zero, so tag as nan. got_tag: ret //get_reg_tag endp // ************************************************************************ // test status bit group: u_masked?, z_masked?, d_masked?, i_masked?, // o_masked?, affine_infinity?, p_error?, i_error?, d_error?, // set_i_masked?, set_d_masked? // // inputs: no input values are required. // // outputs: all boolean function return the complemented bit value // in the zf. (test with jz on bit = 0.) // ************************************************************************ ALIGN u_masked_: //proc testb underflow_mask,%gs:sr_masks // test the u mask ret //u_masked_ endp // ALIGN set_d_masked_: //proc call set_d_error // set the d error d_masked_: testb denorm_mask,%gs:sr_masks // test the d mask ret //set_d_masked_ endp // ALIGN set_i_masked_: //proc call set_i_error // set the i error i_masked_: testb invalid_mask,%gs:sr_masks // test the i mask ret //set_i_masked_ endp // ALIGN o_masked_: //proc testb overflow_mask,%gs:sr_masks // test the o mask ret //o_masked_ endp // ALIGN affine_infinity_: //proc testb infinity_control_mask,%gs:sr_controls // test ic ret //affine_infinity_ endp // ALIGN p_error_: //proc testb $inexact_mask,%gs:sr_errors // test the p error ret //p_error_ endp // ALIGN i_error_: //proc testb invalid_mask,%gs:sr_errors // test the i error ret //i_error_ endp // ALIGN d_error_: //proc testb denorm_mask,%gs:sr_errors // test the d error ret //d_error_ endp // ************************************************************************ // set and reset bit group: set_p_error, set_u_error, set_o_error // set_z_masked?, set_i_error, set_d_error, clear_s_bit, clear_z_bit // set_s_bit, set_z_bit, set_a_bit, clear_a_bit, set_c_bit, clear_c_bit // clear_cond_bits, clear_p_error, set_stk_u_error, set_stk_o_error // // inputs: no input values are required. // // outputs: all procedures set or reset the indicated status bit // ************************************************************************ ALIGN set_stk_u_error: //proc orb invalid_mask+zero_mask,%gs:sr_errors andb $~a_mask,%gs:sr_flags // clear the a-bit ret //set_stk_u_error endp // ALIGN set_stk_o_error: //proc orb invalid_mask+zero_mask,%gs:sr_errors orb $a_mask,%gs:sr_flags // set the a-bit ret //set_stk_o_error endp // ALIGN set_p_error: //proc orb $inexact_mask,%gs:sr_errors // set the p-error ret //set_p_error endp // ALIGN set_u_error: //proc orb underflow_mask,%gs:sr_errors // set the u-error ret //set_u_error endp // ALIGN set_o_error: //proc orb overflow_mask,%gs:sr_errors // set the o-error ret //set_o_error endp // ALIGN set_i_error: //proc orb invalid_mask,%gs:sr_errors // set the i-error ret //set_i_error endp // ALIGN set_d_error: //proc orb denorm_mask,%gs:sr_errors // set the d-error ret //set_d_error endp // ALIGN set_z_masked_: //proc orb zero_divide_mask,%gs:sr_errors // set the z-error testb zero_divide_mask,%gs:sr_masks // test the z mask ret //set_z_masked_ endp // ALIGN set_s_bit: //proc orb $sign_mask,%gs:sr_flags // set the s-bit ret //set_s_bit endp // ALIGN set_z_bit: //proc orb $zero_mask,%gs:sr_flags // set the z-bit ret //set_z_bit endp // ALIGN set_a_bit: //proc orb $a_mask,%gs:sr_flags // set the a-bit ret //set_a_bit endp // ALIGN set_c_bit: //proc orb $c_mask,%gs:sr_flags // set the c-bit ret //set_c_bit endp // ALIGN clear_s_bit: //proc andb $~sign_mask,%gs:sr_flags // clear the s-bit ret //clear_s_bit endp // ALIGN clear_z_bit: //proc andb $~zero_mask,%gs:sr_flags // clear the z-bit ret //clear_z_bit endp // ALIGN clear_a_bit: //proc andb $~a_mask,%gs:sr_flags // clear the a-bit ret //clear_a_bit endp // ALIGN clear_cond_bits: //proc andb $~(c_mask+zero_mask+sign_mask+a_mask),%gs:sr_flags ret // clear all condition bits //clear_cond_bits endp // ALIGN clear_c_bit: //proc andb $~c_mask,%gs:sr_flags // clear the c-bit ret //clear_c_bit endp // ALIGN clear_p_error: //proc andb $~inexact_mask ,%gs:sr_errors // clear the p-error ret //clear_p_error endp // // ************************************************************************ // pop_free: // function: // pops the stack and/or frees the register(s) as required // // ************************************************************************ ALIGN pop_free: //proc call i_masked_ // is invalid masked? jnz check_op1 // if so, forget error call i_error_ // check for i-error jnz common_return // if error, dont pop free_reg: check_op1: movb op1_use_up(%ebp),%al // pop or free op1 call process_use_up movb op2_use_up(%ebp),%al // pop or free op2 process_use_up: cmpb pop_stack,%al // is it a pop_stack? je pop_it // yes, process it xorb free,%al // no, is it free reg? jnz exit_process // no, done with use_up call get_top // yes, get top pointer addb reg_num(%ebp),%al // convert relative num andb $0x07,%al // to absolute reg num empty_reg_tag: movb %al,%cl // cl = reg number movb $empty,%al // al = new tag value store_reg_tag: shlb $1,%cl // bit count = 2 * reg num rorw %cl,%gs:sr_tags // rotate tag to low bits andb $~empty,%gs:sr_tags // clear old reg num tag andb $empty,%al // clear bits 2-7 of new tag orb %al,%gs:sr_tags // store new reg num tag and rolw %cl,%gs:sr_tags // rotate the tag word back exit_process: ret pop_it: call get_top // pop the stack once // the following six instructions have been commented out to prevent // an invalid operation from being signaled when the 87 tos is subject // to a freep st(i) (*6 in the 80387 t-spec). in other words, it will // be o.k. to free st(0) and decrement stackpointer, so it will also be // o.k. to free an already empty st(0). // call get_reg_tag ; get register tag // cmp al,empty ; is the top empty? // jne pop_ok ; no, stack may be popped // call set_i_masked? ; yes, stack error // jz exit_process ; abort if unmasked //pop_ok: // call get_top call empty_reg_tag //set tag of top empty //pop_free endp ; enter incr_top // // ************************************************************************** // incr_top: // function: // increments stack pointer // // ************************************************************************** FALLSTHRU incr_top: //proc movb $0x08,%cl // load increment top constant jmp adjust_top // merge with decr_top ALIGN //incr_top endp // ************************************************************************** // decr_top: // function: // decrements stack pointer // // ************************************************************************** ALIGN decr_top: //proc movb $0x38,%cl // load decrement top constant adjust_top: movb %gs:sr_flags,%al // get old top andb $top_mask,%al xorb %al,%gs:sr_flags // clear old top field addb %cl,%al // increment/decrement top andb $top_mask,%al // mask off bits 6-7 orb %al,%gs:sr_flags // store new top field common_return: ret //decr_top endp // // ****************************************************************************** // restore_status: // function: // implements the 80387 ldenv instruction. // restores status register from memory. // // ********************************************************************** ALIGN restore_status: //proc push %ds // save %ds push %gs pop %es // load destination base lds mem_operand_pointer(%ebp),%esi // load environment pointer mov $sr_masks,%edi // load dest offset mov $0x0007,%ecx // load environment from memory cmpb $1,oprnd_siz32(%ebp) //is it a 32 bit operand jne restore_status16 //no restore 16 bit status FAST_MOVSL_ES pop %ds orb $0x40,%gs:sr_masks // set stack mask jmp correct_tag_word ALIGN restore_status16: //16 bit protected mode movsw // mov words inc %edi inc %edi loop restore_status16 // --------- //------------------------------------------------------------------------ //.. pushad //.. push ds //..restore_status32: //.. push esi //.. call fpfulong //.. pop esi //.. stosd //.. add esi,4 //.. loop restore_status32 //.. pop ds //.. popad //.. cld //.. ret //..restore_status16: //.. pushad //.. push ds //..restor_loop: //.. push esi //.. call fpfushort //.. pop esi //.. stosw //.. add esi,2 //.. add edi,2 //.. loop restor_loop //.. pop ds //.. popad //.. cld //--------------------------------------------------------------------- pop %ds orb $0x40,%gs:sr_masks // set stack mask correct_tag_word: mov $8,%ecx xor %ebx,%ebx set_tags_loop: //looping through physical locations of 0-7 regs mov $10,%eax mul %ebx mov $sr_regstack,%esi add %eax,%esi mov $0x00000003,%eax and %gs:sr_tags,%eax cmp $3,%eax je loop_back movw %gs:8(%esi),%ax andw $0x7fff,%ax // strip off sign bit jz expon_zero // branch if exponent 0 testb $0x80,%gs:7(%esi) jnz max_expon_ movb $2,%dl // we have an jmp set_tag // unsupported format ALIGN max_expon_: cmpw $0x7fff,%ax // check for invalid je not_validx // or infinity movb $0,%dl // operand is valid jmp set_tag ALIGN not_validx: movb $2,%dl jmp set_tag ALIGN expon_zero: mov %gs:4(%esi),%eax or %gs:(%esi),%eax movb $1,%dl // set tag to special jz set_tag // if number is +/- 0 movb $2,%dl // set tag to denormd set_tag: andb $~empty,%gs:sr_tags // clear old reg num tag orb %dl,%gs:sr_tags // store new reg num tag and loop_back: rorw $2,%gs:sr_tags // get next two bits inc %ebx loop set_tags_loop ret //restore_status endp // ************************************************************************** // init: // function: // implements 80387 init instruction. intializes // status register including mode word and error mask. // // *********************************************************************** ALIGN init: //proc movl $0x137f,%eax // initialize mode word movw %ax,%gs:sr_masks movl $0xffffffff,%ax // ax = 0ffffh movw %ax,%gs:sr_tags // register tags = empty xor %eax,%eax // clear a reg movw %ax,%gs:sr_errors // clear the error flags // and %gs:sr_flags,not top_mask ; top of stack = 0, cbit=0 ret //init endp // *********************************************************************** // ldcw: // function: // implements 80387 ldcw instruction. 80387 control word // loaded (from memory location specified in instruction). // // *********************************************************************** ALIGN ldcw: //proc les mem_operand_pointer(%ebp),%ebx //get new mode word movw %es:(%ebx),%ax //.. //.. pushad //.. push es //.. push ebx //.. call fpfushort //.. pop ebx //.. pop es //.. popad //.. cld //.. orw $0x40,%ax // set stack mask movw %ax,%gs:sr_masks // store in status reg ret //ldcw endp // ********************************************************************** // stenv: // function: // implements 80387 fstenv instruction. 80387 environmemt // stored (in memory location specified in the instruction). // // ********************************************************************** ALIGN stenv: //proc call save_status // store status to memory orb $0x07f,%gs:sr_masks // set all individual masks ret //stenv endp // ********************************************************************** // clex: // function: // clears all 80387 errors set in status register // // ********************************************************************** ALIGN clex: //proc movb $0,%gs:sr_errors // clear error byte ret //clex endp // ********************************************************************** // stsw // function: // stores status word in memory location. (i.e., implements // fstsw instruction.) also implements 'fstsw ax'. // // ********************************************************************** ALIGN stsw: //proc movb op2_location(%ebp),%al // load op2 location cmpb $reg,%al // is this fstsw ax? movw %gs:sr_errors,%ax // get status word je stsw_ax // branch on fstsw ax store_word: les mem_operand_pointer(%ebp),%ebx movw %ax,%es:(%ebx) // store status to memory //.. pushad //.. push es //.. push ebx //.. push ax //.. call fpsushort //.. add esp,12 //.. popad //.. cld //.. ret stsw_ax: movw %ax,saved_eax(%ebp) // store into register ax // above instruction left for completeness but the ax // really has to be restored to the EAX above the global // re-entrant segment // movl %eax, (offset_eax)(%ebp) ret //stsw endp // ********************************************************************* // stcw: // function: // stores control word in memory location. (i.e., implements // fstcw instruction.) // // ********************************************************************* ALIGN stcw: //proc movw %gs:sr_masks,%ax //get control word andw $0x1f7f,%ax orw $0x1040,%ax //set/reset reserved bits jmp store_word //store it ALIGN //stcw endp // ********************************************************************* // save_status: // function: // saves status register to location specified by // memory operand pointer(in es:di) // // ********************************************************************* ALIGN save_status: //proc push %ds // save %ds push %gs pop %ds // and set it to address sr_masks andw $0x1f7f,%gs:sr_masks orw $0x1040,%gs:sr_masks //set/reset reserved bits mov $sr_masks,%esi // load source offset les mem_operand_pointer(%ebp),%edi // load destination pointer mov $0x0007,%ecx cmpb $1,oprnd_siz32(%ebp) jne save_status16 FAST_MOVSL_ES pop %ds // restore %ds ret ALIGN save_status16: //16 bit protected mode movsw // mov words inc %esi inc %esi loop save_status16 //------------------------------------------------------------------------ //.. pushad //.. push es //..save_status32: //.. push edi //.. push dword ptr (esi) //.. call fpsulong //.. add esp,8 //.. add esi,4 //.. add edi,4 //.. loop save_status32 //.. pop es //.. popad //.. cld //.. ret //..save_status16: //.. pushad //.. push es //..save_loop: //.. push edi //.. push word ptr (esi) //.. call fpsushort //.. add esp,8 //.. add edi,2 //.. add esi,4 //.. loop save_loop //.. pop es //.. popad //.. cld pop %ds // restore %ds ret //save_status endp // //a_med ends // // end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.