mirror of
https://github.com/open-simh/simh.git
synced 2026-04-26 04:07:23 +00:00
Various simulators: Set line endings to CRLF for consistency, remove stray tabs
Project standard source code has tabs converted to spaces and CRLF line endings. Other text files have CRLF line endings.
This commit is contained in:
committed by
Paul Koning
parent
f1f8cf9cb1
commit
decbe5b76b
@@ -1,313 +1,313 @@
|
||||
Example M68k Program
|
||||
====================
|
||||
|
||||
As an example, I'll build an imaginary hardware platform.
|
||||
|
||||
The system is fairly simple, comprising a 68000, an input device, an output
|
||||
device, a non-maskable-interrupt device, and an interrupt controller.
|
||||
|
||||
The input device receives input from the user and asserts its interrupt
|
||||
request line until its value is read. Reading from the input device's
|
||||
memory-mapped port will both clear its interrupt request and read an ASCII
|
||||
representation (8 bits) of what the user entered.
|
||||
|
||||
The output device reads value when it is selected through its memory-mapped
|
||||
port and outputs it to a display. The value it reads will be interpreted as
|
||||
an ASCII value and output to the display. The output device is fairly slow
|
||||
(it can only process 1 byte per second), and so it asserts its interrupt
|
||||
request line when it is ready to receive a byte. Writing to the output device
|
||||
sends a byte to it. If the output device is not ready, the write is ignored.
|
||||
Reading from the output device returns 0 and clears its interrupt request line
|
||||
until another byte is written to it and 1 second elapses.
|
||||
|
||||
The non-maskable-interrupt (NMI) device, as can be surmised from the name,
|
||||
generates a non-maskable-interrupt. This is connected to some kind of external
|
||||
switch that the user can push to generate a NMI.
|
||||
|
||||
Since there are 3 devices interrupting the CPU, an interrupt controller is
|
||||
needed. The interrupt controller takes 7 inputs and encodes the highest
|
||||
priority asserted line on the 3 output pins. the input device is wired to IN2
|
||||
and the output device is wired to IN1 on the controller. The NMI device is
|
||||
wired to IN7 and all the other inputs are wired low.
|
||||
|
||||
The bus is also connected to a 1K ROM and a 256 byte RAM.
|
||||
|
||||
Beware: This platform places ROM and RAM in the same address range and uses
|
||||
the FC pins to select the correct address space!
|
||||
(You didn't expect me to make it easy, did you? =)
|
||||
|
||||
|
||||
|
||||
Schematic
|
||||
---------
|
||||
|
||||
NMI TIED
|
||||
SWITCH LOW
|
||||
| |
|
||||
| +-+-+-+
|
||||
| | | | | +------------------------------------------------+
|
||||
| | | | | | +------------------------------------+ |
|
||||
| | | | | | | | |
|
||||
+-------------+ | |
|
||||
|7 6 5 4 3 2 1| | |
|
||||
| | | |
|
||||
| INT CONTRLR | | |
|
||||
| | | |
|
||||
|i i i | | |
|
||||
|2 1 0 | | |
|
||||
+-------------+ | |
|
||||
| | | | |
|
||||
| | | +--------------------------------+--+ | |
|
||||
o o o | | | | |
|
||||
+--------------+ +-------+ +----------+ +---------+ +----------+
|
||||
| I I I a | | | | | | r a i | | i |
|
||||
| 2 1 0 23 | | | | | | e c | | |
|
||||
| | | | | | | a k | | |
|
||||
| | | | | | | d | | |
|
||||
| | | | | | | | | |
|
||||
| M68000 | | ROM | | RAM | | IN | | OUT |
|
||||
| | | | | | | | | |
|
||||
| a9|--|a9 |--| |--| |--| |
|
||||
| a8|--|a8 |--| |--| |--| |
|
||||
| a7|--|a7 |--|a7 |--| |--| |
|
||||
| a6|--|a6 |--|a6 |--| |--| |
|
||||
| a5|--|a5 |--|a5 |--| |--| |
|
||||
| a4|--|a4 |--|a4 |--| |--| |
|
||||
| a3|--|a3 |--|a3 |--| |--| |
|
||||
| a2|--|a2 |--|a2 |--| |--| |
|
||||
| a1|--|a1 |--|a1 |--| |--| |
|
||||
| a0|--|a0 |--|a0 |--| |--| |
|
||||
| | | | | | | | | |
|
||||
| d15|--|d15 |--|d15 |--| |--| |
|
||||
| d14|--|d14 |--|d14 |--| |--| |
|
||||
| d13|--|d13 |--|d13 |--| |--| |
|
||||
| d12|--|d12 |--|d12 |--| |--| |
|
||||
| d11|--|d11 |--|d11 |--| |--| |
|
||||
| d10|--|d10 |--|d10 |--| |--| |
|
||||
| d9|--|d9 |--|d9 |--| |--| |
|
||||
| d8|--|d8 |--|d8 |--| |--| |
|
||||
| d7|--|d7 |--|d7 |--|d7 |--|d7 |
|
||||
| d6|--|d6 |--|d6 |--|d6 |--|d6 |
|
||||
| d5|--|d5 |--|d5 |--|d5 |--|d5 |
|
||||
| d4|--|d4 |--|d4 |--|d4 |--|d4 |
|
||||
| d3|--|d3 |--|d3 |--|d3 |--|d3 |
|
||||
| d2|--|d2 |--|d2 |--|d2 |--|d2 |
|
||||
| d1|--|d1 |--|d1 |--|d1 |--|d1 w |
|
||||
| d0|--|d0 |--|d0 |--|d0 |--|d0 r |
|
||||
| | | | | | | | | i a |
|
||||
| a F F F | | | | | | | | t c |
|
||||
|22 rW 2 1 0 | | cs | | cs rW | | | | e k |
|
||||
+--------------+ +-------+ +----------+ +---------+ +----------+
|
||||
| | | | | | | | | |
|
||||
| | | | | | | | | |
|
||||
| | | | | +-------+ +-----+ | +---+ |
|
||||
| | | | | | IC1 | | IC2 | | |AND| |
|
||||
| | | | | |a b c d| |a b c| | +---+ |
|
||||
| | | | | +-------+ +-----+ | | | |
|
||||
| | | | | | | | | | | | | | +--+
|
||||
| | | | | | | | | | | | | | |
|
||||
| | | | | | | | | | | | | | |
|
||||
| | | | | | | | | | | | | | |
|
||||
| | | | +-----)-)-+-)----)-)-+ | | |
|
||||
| | | +-------)-+---)----)-+ | | |
|
||||
| | +---------+-----)----+ | | |
|
||||
| | | | | |
|
||||
| +------------------+-----------+----------------------+ |
|
||||
| |
|
||||
+-----------------------------------------------------------+
|
||||
|
||||
IC1: output=1 if a=0 and b=1 and c=0 and d=0
|
||||
IC2: output=1 if a=0 and b=0 and c=1
|
||||
|
||||
|
||||
|
||||
Program Listing (program.bin)
|
||||
-----------------------------
|
||||
|
||||
```
|
||||
INPUT_ADDRESS equ $800000
|
||||
OUTPUT_ADDRESS equ $400000
|
||||
CIRCULAR_BUFFER equ $c0
|
||||
CAN_OUTPUT equ $d0
|
||||
STACK_AREA equ $100
|
||||
|
||||
vector_table:
|
||||
00000000 0000 0100 dc.l STACK_AREA * 0: SP
|
||||
00000004 0000 00c0 dc.l init * 1: PC
|
||||
00000008 0000 0148 dc.l unhandled_exception * 2: bus error
|
||||
0000000c 0000 0148 dc.l unhandled_exception * 3: address error
|
||||
00000010 0000 0148 dc.l unhandled_exception * 4: illegal instruction
|
||||
00000014 0000 0148 dc.l unhandled_exception * 5: zero divide
|
||||
00000018 0000 0148 dc.l unhandled_exception * 6: chk
|
||||
0000001c 0000 0148 dc.l unhandled_exception * 7: trapv
|
||||
00000020 0000 0148 dc.l unhandled_exception * 8: privilege violation
|
||||
00000024 0000 0148 dc.l unhandled_exception * 9: trace
|
||||
00000028 0000 0148 dc.l unhandled_exception * 10: 1010
|
||||
0000002c 0000 0148 dc.l unhandled_exception * 11: 1111
|
||||
00000030 0000 0148 dc.l unhandled_exception * 12: -
|
||||
00000034 0000 0148 dc.l unhandled_exception * 13: -
|
||||
00000038 0000 0148 dc.l unhandled_exception * 14: -
|
||||
0000003c 0000 0148 dc.l unhandled_exception * 15: uninitialized interrupt
|
||||
00000040 0000 0148 dc.l unhandled_exception * 16: -
|
||||
00000044 0000 0148 dc.l unhandled_exception * 17: -
|
||||
00000048 0000 0148 dc.l unhandled_exception * 18: -
|
||||
0000004c 0000 0148 dc.l unhandled_exception * 19: -
|
||||
00000050 0000 0148 dc.l unhandled_exception * 20: -
|
||||
00000054 0000 0148 dc.l unhandled_exception * 21: -
|
||||
00000058 0000 0148 dc.l unhandled_exception * 22: -
|
||||
0000005c 0000 0148 dc.l unhandled_exception * 23: -
|
||||
00000060 0000 0148 dc.l unhandled_exception * 24: spurious interrupt
|
||||
00000064 0000 0136 dc.l output_ready * 25: l1 irq
|
||||
00000068 0000 010e dc.l input_ready * 26: l2 irq
|
||||
0000006c 0000 0148 dc.l unhandled_exception * 27: l3 irq
|
||||
00000070 0000 0148 dc.l unhandled_exception * 28: l4 irq
|
||||
00000074 0000 0148 dc.l unhandled_exception * 29: l5 irq
|
||||
00000078 0000 0148 dc.l unhandled_exception * 30: l6 irq
|
||||
0000007c 0000 014e dc.l nmi * 31: l7 irq
|
||||
00000080 0000 0148 dc.l unhandled_exception * 32: trap 0
|
||||
00000084 0000 0148 dc.l unhandled_exception * 33: trap 1
|
||||
00000088 0000 0148 dc.l unhandled_exception * 34: trap 2
|
||||
0000008c 0000 0148 dc.l unhandled_exception * 35: trap 3
|
||||
00000090 0000 0148 dc.l unhandled_exception * 36: trap 4
|
||||
00000094 0000 0148 dc.l unhandled_exception * 37: trap 5
|
||||
00000098 0000 0148 dc.l unhandled_exception * 38: trap 6
|
||||
0000009c 0000 0148 dc.l unhandled_exception * 39: trap 7
|
||||
000000a0 0000 0148 dc.l unhandled_exception * 40: trap 8
|
||||
000000a4 0000 0148 dc.l unhandled_exception * 41: trap 9
|
||||
000000a8 0000 0148 dc.l unhandled_exception * 42: trap 10
|
||||
000000ac 0000 0148 dc.l unhandled_exception * 43: trap 11
|
||||
000000b0 0000 0148 dc.l unhandled_exception * 44: trap 12
|
||||
000000b4 0000 0148 dc.l unhandled_exception * 45: trap 13
|
||||
000000b8 0000 0148 dc.l unhandled_exception * 46: trap 14
|
||||
000000bc 0000 0148 dc.l unhandled_exception * 47: trap 15
|
||||
* This is the end of the useful part of the table.
|
||||
* We will now do the Capcom thing and put code starting at $c0.
|
||||
|
||||
init:
|
||||
* Copy the exception vector table to RAM.
|
||||
000000c0 227c 0000 0000 move.l #0, a1 * a1 is RAM index
|
||||
000000c6 303c 002f move.w #47, d0 * d0 is counter (48 vectors)
|
||||
000000ca 41fa 0006 lea.l (copy_table,PC), a0 * a0 is scratch
|
||||
000000ce 2208 move.l a0, d1 * d1 is ROM index
|
||||
000000d0 4481 neg.l d1
|
||||
copy_table:
|
||||
000000d2 22fb 18fe dc.l $22fb18fe * stoopid as68k generates 020 code here
|
||||
* move.l (copy_table,PC,d1.l), (a1)+
|
||||
000000d6 5841 addq #4, d1
|
||||
000000d8 51c8 fff8 dbf d0, copy_table
|
||||
|
||||
main_init:
|
||||
* Initialize main program
|
||||
000000dc 11fc 0000 00d0 move.b #0, CAN_OUTPUT
|
||||
000000e2 4df8 00c0 lea.l CIRCULAR_BUFFER, a6
|
||||
000000e6 7c00 moveq #0, d6 * output buffer ptr
|
||||
000000e8 7e00 moveq #0, d7 * input buffer ptr
|
||||
000000ea 027c f8ff andi #$f8ff, SR * clear interrupt mask
|
||||
main:
|
||||
* Main program
|
||||
000000ee 4a38 00d0 tst.b CAN_OUTPUT * can we output?
|
||||
000000f2 67fa beq main
|
||||
000000f4 be06 cmp.b d6, d7 * is there data?
|
||||
000000f6 67f6 beq main
|
||||
000000f8 11fc 0000 00d0 move.b #0, CAN_OUTPUT
|
||||
000000fe 13f6 6000 0040 move.b (0,a6,d6.w), OUTPUT_ADDRESS * write data
|
||||
0000
|
||||
00000106 5246 addq #1, d6
|
||||
00000108 0206 000f andi.b #15, d6 * update circular buffer
|
||||
0000010c 60e0 bra main
|
||||
|
||||
|
||||
input_ready:
|
||||
0000010e 2f00 move.l d0, -(a7)
|
||||
00000110 2f01 move.l d1, -(a7)
|
||||
00000112 1239 0080 0000 move.b INPUT_ADDRESS, d1 * read data
|
||||
00000118 1007 move.b d7, d0 * check if buffer full
|
||||
0000011a 5240 addq #1, d0
|
||||
0000011c 0200 000f andi.b #15, d0
|
||||
00000120 bc00 cmp.b d0, d6
|
||||
00000122 6700 000c beq input_ready_quit * throw away if full
|
||||
00000126 1d81 7000 move.b d1, (0,a6,d7.w) * store the data
|
||||
0000012a 5247 addq #1, d7
|
||||
0000012c 0207 000f andi.b #15, d7 * update circular buffer
|
||||
input_ready_quit:
|
||||
00000130 221f move.l (a7)+, d1
|
||||
00000132 201f move.l (a7)+, d0
|
||||
00000134 4e73 rte
|
||||
|
||||
output_ready:
|
||||
00000136 2f00 move.l d0, -(a7)
|
||||
00000138 11fc 0001 00d0 move.b #1, CAN_OUTPUT
|
||||
0000013e 1039 0040 0000 move.b OUTPUT_ADDRESS, d0 * acknowledge the interrupt
|
||||
00000144 201f move.l (a7)+, d0
|
||||
00000146 4e73 rte
|
||||
|
||||
unhandled_exception:
|
||||
00000148 4e72 2700 stop #$2700 * wait for NMI
|
||||
0000014c 60fa bra unhandled_exception * shouldn't get here
|
||||
|
||||
nmi:
|
||||
* perform a soft reset
|
||||
0000014e 46fc 2700 move #$2700, SR * set status register
|
||||
00000152 2e7a feac move.l (vector_table,PC), a7 * reset stack pointer
|
||||
00000156 4e70 reset * reset peripherals
|
||||
00000158 4efa feaa jmp (vector_table+4,PC) * reset program counter
|
||||
|
||||
END
|
||||
```
|
||||
|
||||
|
||||
Compiling the example host environment
|
||||
--------------------------------------
|
||||
|
||||
### DOS
|
||||
|
||||
`osd_dos.c`
|
||||
|
||||
This code was written a long time ago, in another era when DOS environments
|
||||
were still a thing. Thus, the primary interface was designed around the DOS
|
||||
console, which allowed easy control over keyboard input and console echo. If
|
||||
you still have such an environment, compilers such as mingw or djgpp are
|
||||
enough to compile it.
|
||||
|
||||
### Linux
|
||||
|
||||
`osd_linux.c`
|
||||
|
||||
There's now a Linux interface but it's very **very** basic. The terminal echoes
|
||||
back everything you type immediately, which makes the output look weird as the
|
||||
program output mixes with the terminal echo.
|
||||
|
||||
Unfortunately, I don't have enough free time to sort through the
|
||||
termios/ncurses minefield to make it behave better. If you happen to know how
|
||||
to do this sort of thing, please help out by submitting a PR!
|
||||
|
||||
### Other Platforms
|
||||
|
||||
You'll need to make an `osd_xyz.c` for your particular platform to implement
|
||||
`osd_get_key()`, and update the Makefile to handle your particular environment.
|
||||
|
||||
### Building and running
|
||||
|
||||
You'll need a C compiler. GCC or Clang should work fine. MSVC will require you
|
||||
to set up a project (use the makefile as a guide).
|
||||
|
||||
- Type `make`
|
||||
- Type `./sim program.bin`
|
||||
- Interact with program.bin using the keyboard.
|
||||
|
||||
#### Keys:
|
||||
|
||||
ESC - quits the simulator
|
||||
~ - generates an NMI interrupt
|
||||
Any other key - Genearate input for the input device
|
||||
|
||||
|
||||
### Note
|
||||
|
||||
I've cheated a bit in the emulation. There is no speed control to set the
|
||||
speed the CPU runs at; it simply runs as fast as your processor can run it.
|
||||
|
||||
To add speed control, you will need a high-precision timestamp function
|
||||
(like the RDTSC instruction for newer Pentium CPUs) and a bit of arithmetic
|
||||
to make the cycles argument for m68k_execute(). I'll leave that as an
|
||||
excercise to the reader.
|
||||
Example M68k Program
|
||||
====================
|
||||
|
||||
As an example, I'll build an imaginary hardware platform.
|
||||
|
||||
The system is fairly simple, comprising a 68000, an input device, an output
|
||||
device, a non-maskable-interrupt device, and an interrupt controller.
|
||||
|
||||
The input device receives input from the user and asserts its interrupt
|
||||
request line until its value is read. Reading from the input device's
|
||||
memory-mapped port will both clear its interrupt request and read an ASCII
|
||||
representation (8 bits) of what the user entered.
|
||||
|
||||
The output device reads value when it is selected through its memory-mapped
|
||||
port and outputs it to a display. The value it reads will be interpreted as
|
||||
an ASCII value and output to the display. The output device is fairly slow
|
||||
(it can only process 1 byte per second), and so it asserts its interrupt
|
||||
request line when it is ready to receive a byte. Writing to the output device
|
||||
sends a byte to it. If the output device is not ready, the write is ignored.
|
||||
Reading from the output device returns 0 and clears its interrupt request line
|
||||
until another byte is written to it and 1 second elapses.
|
||||
|
||||
The non-maskable-interrupt (NMI) device, as can be surmised from the name,
|
||||
generates a non-maskable-interrupt. This is connected to some kind of external
|
||||
switch that the user can push to generate a NMI.
|
||||
|
||||
Since there are 3 devices interrupting the CPU, an interrupt controller is
|
||||
needed. The interrupt controller takes 7 inputs and encodes the highest
|
||||
priority asserted line on the 3 output pins. the input device is wired to IN2
|
||||
and the output device is wired to IN1 on the controller. The NMI device is
|
||||
wired to IN7 and all the other inputs are wired low.
|
||||
|
||||
The bus is also connected to a 1K ROM and a 256 byte RAM.
|
||||
|
||||
Beware: This platform places ROM and RAM in the same address range and uses
|
||||
the FC pins to select the correct address space!
|
||||
(You didn't expect me to make it easy, did you? =)
|
||||
|
||||
|
||||
|
||||
Schematic
|
||||
---------
|
||||
|
||||
NMI TIED
|
||||
SWITCH LOW
|
||||
| |
|
||||
| +-+-+-+
|
||||
| | | | | +------------------------------------------------+
|
||||
| | | | | | +------------------------------------+ |
|
||||
| | | | | | | | |
|
||||
+-------------+ | |
|
||||
|7 6 5 4 3 2 1| | |
|
||||
| | | |
|
||||
| INT CONTRLR | | |
|
||||
| | | |
|
||||
|i i i | | |
|
||||
|2 1 0 | | |
|
||||
+-------------+ | |
|
||||
| | | | |
|
||||
| | | +--------------------------------+--+ | |
|
||||
o o o | | | | |
|
||||
+--------------+ +-------+ +----------+ +---------+ +----------+
|
||||
| I I I a | | | | | | r a i | | i |
|
||||
| 2 1 0 23 | | | | | | e c | | |
|
||||
| | | | | | | a k | | |
|
||||
| | | | | | | d | | |
|
||||
| | | | | | | | | |
|
||||
| M68000 | | ROM | | RAM | | IN | | OUT |
|
||||
| | | | | | | | | |
|
||||
| a9|--|a9 |--| |--| |--| |
|
||||
| a8|--|a8 |--| |--| |--| |
|
||||
| a7|--|a7 |--|a7 |--| |--| |
|
||||
| a6|--|a6 |--|a6 |--| |--| |
|
||||
| a5|--|a5 |--|a5 |--| |--| |
|
||||
| a4|--|a4 |--|a4 |--| |--| |
|
||||
| a3|--|a3 |--|a3 |--| |--| |
|
||||
| a2|--|a2 |--|a2 |--| |--| |
|
||||
| a1|--|a1 |--|a1 |--| |--| |
|
||||
| a0|--|a0 |--|a0 |--| |--| |
|
||||
| | | | | | | | | |
|
||||
| d15|--|d15 |--|d15 |--| |--| |
|
||||
| d14|--|d14 |--|d14 |--| |--| |
|
||||
| d13|--|d13 |--|d13 |--| |--| |
|
||||
| d12|--|d12 |--|d12 |--| |--| |
|
||||
| d11|--|d11 |--|d11 |--| |--| |
|
||||
| d10|--|d10 |--|d10 |--| |--| |
|
||||
| d9|--|d9 |--|d9 |--| |--| |
|
||||
| d8|--|d8 |--|d8 |--| |--| |
|
||||
| d7|--|d7 |--|d7 |--|d7 |--|d7 |
|
||||
| d6|--|d6 |--|d6 |--|d6 |--|d6 |
|
||||
| d5|--|d5 |--|d5 |--|d5 |--|d5 |
|
||||
| d4|--|d4 |--|d4 |--|d4 |--|d4 |
|
||||
| d3|--|d3 |--|d3 |--|d3 |--|d3 |
|
||||
| d2|--|d2 |--|d2 |--|d2 |--|d2 |
|
||||
| d1|--|d1 |--|d1 |--|d1 |--|d1 w |
|
||||
| d0|--|d0 |--|d0 |--|d0 |--|d0 r |
|
||||
| | | | | | | | | i a |
|
||||
| a F F F | | | | | | | | t c |
|
||||
|22 rW 2 1 0 | | cs | | cs rW | | | | e k |
|
||||
+--------------+ +-------+ +----------+ +---------+ +----------+
|
||||
| | | | | | | | | |
|
||||
| | | | | | | | | |
|
||||
| | | | | +-------+ +-----+ | +---+ |
|
||||
| | | | | | IC1 | | IC2 | | |AND| |
|
||||
| | | | | |a b c d| |a b c| | +---+ |
|
||||
| | | | | +-------+ +-----+ | | | |
|
||||
| | | | | | | | | | | | | | +--+
|
||||
| | | | | | | | | | | | | | |
|
||||
| | | | | | | | | | | | | | |
|
||||
| | | | | | | | | | | | | | |
|
||||
| | | | +-----)-)-+-)----)-)-+ | | |
|
||||
| | | +-------)-+---)----)-+ | | |
|
||||
| | +---------+-----)----+ | | |
|
||||
| | | | | |
|
||||
| +------------------+-----------+----------------------+ |
|
||||
| |
|
||||
+-----------------------------------------------------------+
|
||||
|
||||
IC1: output=1 if a=0 and b=1 and c=0 and d=0
|
||||
IC2: output=1 if a=0 and b=0 and c=1
|
||||
|
||||
|
||||
|
||||
Program Listing (program.bin)
|
||||
-----------------------------
|
||||
|
||||
```
|
||||
INPUT_ADDRESS equ $800000
|
||||
OUTPUT_ADDRESS equ $400000
|
||||
CIRCULAR_BUFFER equ $c0
|
||||
CAN_OUTPUT equ $d0
|
||||
STACK_AREA equ $100
|
||||
|
||||
vector_table:
|
||||
00000000 0000 0100 dc.l STACK_AREA * 0: SP
|
||||
00000004 0000 00c0 dc.l init * 1: PC
|
||||
00000008 0000 0148 dc.l unhandled_exception * 2: bus error
|
||||
0000000c 0000 0148 dc.l unhandled_exception * 3: address error
|
||||
00000010 0000 0148 dc.l unhandled_exception * 4: illegal instruction
|
||||
00000014 0000 0148 dc.l unhandled_exception * 5: zero divide
|
||||
00000018 0000 0148 dc.l unhandled_exception * 6: chk
|
||||
0000001c 0000 0148 dc.l unhandled_exception * 7: trapv
|
||||
00000020 0000 0148 dc.l unhandled_exception * 8: privilege violation
|
||||
00000024 0000 0148 dc.l unhandled_exception * 9: trace
|
||||
00000028 0000 0148 dc.l unhandled_exception * 10: 1010
|
||||
0000002c 0000 0148 dc.l unhandled_exception * 11: 1111
|
||||
00000030 0000 0148 dc.l unhandled_exception * 12: -
|
||||
00000034 0000 0148 dc.l unhandled_exception * 13: -
|
||||
00000038 0000 0148 dc.l unhandled_exception * 14: -
|
||||
0000003c 0000 0148 dc.l unhandled_exception * 15: uninitialized interrupt
|
||||
00000040 0000 0148 dc.l unhandled_exception * 16: -
|
||||
00000044 0000 0148 dc.l unhandled_exception * 17: -
|
||||
00000048 0000 0148 dc.l unhandled_exception * 18: -
|
||||
0000004c 0000 0148 dc.l unhandled_exception * 19: -
|
||||
00000050 0000 0148 dc.l unhandled_exception * 20: -
|
||||
00000054 0000 0148 dc.l unhandled_exception * 21: -
|
||||
00000058 0000 0148 dc.l unhandled_exception * 22: -
|
||||
0000005c 0000 0148 dc.l unhandled_exception * 23: -
|
||||
00000060 0000 0148 dc.l unhandled_exception * 24: spurious interrupt
|
||||
00000064 0000 0136 dc.l output_ready * 25: l1 irq
|
||||
00000068 0000 010e dc.l input_ready * 26: l2 irq
|
||||
0000006c 0000 0148 dc.l unhandled_exception * 27: l3 irq
|
||||
00000070 0000 0148 dc.l unhandled_exception * 28: l4 irq
|
||||
00000074 0000 0148 dc.l unhandled_exception * 29: l5 irq
|
||||
00000078 0000 0148 dc.l unhandled_exception * 30: l6 irq
|
||||
0000007c 0000 014e dc.l nmi * 31: l7 irq
|
||||
00000080 0000 0148 dc.l unhandled_exception * 32: trap 0
|
||||
00000084 0000 0148 dc.l unhandled_exception * 33: trap 1
|
||||
00000088 0000 0148 dc.l unhandled_exception * 34: trap 2
|
||||
0000008c 0000 0148 dc.l unhandled_exception * 35: trap 3
|
||||
00000090 0000 0148 dc.l unhandled_exception * 36: trap 4
|
||||
00000094 0000 0148 dc.l unhandled_exception * 37: trap 5
|
||||
00000098 0000 0148 dc.l unhandled_exception * 38: trap 6
|
||||
0000009c 0000 0148 dc.l unhandled_exception * 39: trap 7
|
||||
000000a0 0000 0148 dc.l unhandled_exception * 40: trap 8
|
||||
000000a4 0000 0148 dc.l unhandled_exception * 41: trap 9
|
||||
000000a8 0000 0148 dc.l unhandled_exception * 42: trap 10
|
||||
000000ac 0000 0148 dc.l unhandled_exception * 43: trap 11
|
||||
000000b0 0000 0148 dc.l unhandled_exception * 44: trap 12
|
||||
000000b4 0000 0148 dc.l unhandled_exception * 45: trap 13
|
||||
000000b8 0000 0148 dc.l unhandled_exception * 46: trap 14
|
||||
000000bc 0000 0148 dc.l unhandled_exception * 47: trap 15
|
||||
* This is the end of the useful part of the table.
|
||||
* We will now do the Capcom thing and put code starting at $c0.
|
||||
|
||||
init:
|
||||
* Copy the exception vector table to RAM.
|
||||
000000c0 227c 0000 0000 move.l #0, a1 * a1 is RAM index
|
||||
000000c6 303c 002f move.w #47, d0 * d0 is counter (48 vectors)
|
||||
000000ca 41fa 0006 lea.l (copy_table,PC), a0 * a0 is scratch
|
||||
000000ce 2208 move.l a0, d1 * d1 is ROM index
|
||||
000000d0 4481 neg.l d1
|
||||
copy_table:
|
||||
000000d2 22fb 18fe dc.l $22fb18fe * stoopid as68k generates 020 code here
|
||||
* move.l (copy_table,PC,d1.l), (a1)+
|
||||
000000d6 5841 addq #4, d1
|
||||
000000d8 51c8 fff8 dbf d0, copy_table
|
||||
|
||||
main_init:
|
||||
* Initialize main program
|
||||
000000dc 11fc 0000 00d0 move.b #0, CAN_OUTPUT
|
||||
000000e2 4df8 00c0 lea.l CIRCULAR_BUFFER, a6
|
||||
000000e6 7c00 moveq #0, d6 * output buffer ptr
|
||||
000000e8 7e00 moveq #0, d7 * input buffer ptr
|
||||
000000ea 027c f8ff andi #$f8ff, SR * clear interrupt mask
|
||||
main:
|
||||
* Main program
|
||||
000000ee 4a38 00d0 tst.b CAN_OUTPUT * can we output?
|
||||
000000f2 67fa beq main
|
||||
000000f4 be06 cmp.b d6, d7 * is there data?
|
||||
000000f6 67f6 beq main
|
||||
000000f8 11fc 0000 00d0 move.b #0, CAN_OUTPUT
|
||||
000000fe 13f6 6000 0040 move.b (0,a6,d6.w), OUTPUT_ADDRESS * write data
|
||||
0000
|
||||
00000106 5246 addq #1, d6
|
||||
00000108 0206 000f andi.b #15, d6 * update circular buffer
|
||||
0000010c 60e0 bra main
|
||||
|
||||
|
||||
input_ready:
|
||||
0000010e 2f00 move.l d0, -(a7)
|
||||
00000110 2f01 move.l d1, -(a7)
|
||||
00000112 1239 0080 0000 move.b INPUT_ADDRESS, d1 * read data
|
||||
00000118 1007 move.b d7, d0 * check if buffer full
|
||||
0000011a 5240 addq #1, d0
|
||||
0000011c 0200 000f andi.b #15, d0
|
||||
00000120 bc00 cmp.b d0, d6
|
||||
00000122 6700 000c beq input_ready_quit * throw away if full
|
||||
00000126 1d81 7000 move.b d1, (0,a6,d7.w) * store the data
|
||||
0000012a 5247 addq #1, d7
|
||||
0000012c 0207 000f andi.b #15, d7 * update circular buffer
|
||||
input_ready_quit:
|
||||
00000130 221f move.l (a7)+, d1
|
||||
00000132 201f move.l (a7)+, d0
|
||||
00000134 4e73 rte
|
||||
|
||||
output_ready:
|
||||
00000136 2f00 move.l d0, -(a7)
|
||||
00000138 11fc 0001 00d0 move.b #1, CAN_OUTPUT
|
||||
0000013e 1039 0040 0000 move.b OUTPUT_ADDRESS, d0 * acknowledge the interrupt
|
||||
00000144 201f move.l (a7)+, d0
|
||||
00000146 4e73 rte
|
||||
|
||||
unhandled_exception:
|
||||
00000148 4e72 2700 stop #$2700 * wait for NMI
|
||||
0000014c 60fa bra unhandled_exception * shouldn't get here
|
||||
|
||||
nmi:
|
||||
* perform a soft reset
|
||||
0000014e 46fc 2700 move #$2700, SR * set status register
|
||||
00000152 2e7a feac move.l (vector_table,PC), a7 * reset stack pointer
|
||||
00000156 4e70 reset * reset peripherals
|
||||
00000158 4efa feaa jmp (vector_table+4,PC) * reset program counter
|
||||
|
||||
END
|
||||
```
|
||||
|
||||
|
||||
Compiling the example host environment
|
||||
--------------------------------------
|
||||
|
||||
### DOS
|
||||
|
||||
`osd_dos.c`
|
||||
|
||||
This code was written a long time ago, in another era when DOS environments
|
||||
were still a thing. Thus, the primary interface was designed around the DOS
|
||||
console, which allowed easy control over keyboard input and console echo. If
|
||||
you still have such an environment, compilers such as mingw or djgpp are
|
||||
enough to compile it.
|
||||
|
||||
### Linux
|
||||
|
||||
`osd_linux.c`
|
||||
|
||||
There's now a Linux interface but it's very **very** basic. The terminal echoes
|
||||
back everything you type immediately, which makes the output look weird as the
|
||||
program output mixes with the terminal echo.
|
||||
|
||||
Unfortunately, I don't have enough free time to sort through the
|
||||
termios/ncurses minefield to make it behave better. If you happen to know how
|
||||
to do this sort of thing, please help out by submitting a PR!
|
||||
|
||||
### Other Platforms
|
||||
|
||||
You'll need to make an `osd_xyz.c` for your particular platform to implement
|
||||
`osd_get_key()`, and update the Makefile to handle your particular environment.
|
||||
|
||||
### Building and running
|
||||
|
||||
You'll need a C compiler. GCC or Clang should work fine. MSVC will require you
|
||||
to set up a project (use the makefile as a guide).
|
||||
|
||||
- Type `make`
|
||||
- Type `./sim program.bin`
|
||||
- Interact with program.bin using the keyboard.
|
||||
|
||||
#### Keys:
|
||||
|
||||
ESC - quits the simulator
|
||||
~ - generates an NMI interrupt
|
||||
Any other key - Genearate input for the input device
|
||||
|
||||
|
||||
### Note
|
||||
|
||||
I've cheated a bit in the emulation. There is no speed control to set the
|
||||
speed the CPU runs at; it simply runs as fast as your processor can run it.
|
||||
|
||||
To add speed control, you will need a high-precision timestamp function
|
||||
(like the RDTSC instruction for newer Pentium CPUs) and a bit of arithmetic
|
||||
to make the cycles argument for m68k_execute(). I'll leave that as an
|
||||
excercise to the reader.
|
||||
|
||||
@@ -1,78 +1,78 @@
|
||||
MAME note: this package is derived from the following original SoftFloat
|
||||
package and has been "re-packaged" to work with MAME's conventions and
|
||||
build system. The source files come from bits64/ and bits64/templates
|
||||
in the original distribution as MAME requires a compiler with a 64-bit
|
||||
integer type.
|
||||
|
||||
|
||||
Package Overview for SoftFloat Release 2b
|
||||
|
||||
John R. Hauser
|
||||
2002 May 27
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Overview
|
||||
|
||||
SoftFloat is a software implementation of floating-point that conforms to
|
||||
the IEC/IEEE Standard for Binary Floating-Point Arithmetic. SoftFloat is
|
||||
distributed in the form of C source code. Compiling the SoftFloat sources
|
||||
generates two things:
|
||||
|
||||
-- A SoftFloat object file (typically `softfloat.o') containing the complete
|
||||
set of IEC/IEEE floating-point routines.
|
||||
|
||||
-- A `timesoftfloat' program for evaluating the speed of the SoftFloat
|
||||
routines. (The SoftFloat module is linked into this program.)
|
||||
|
||||
The SoftFloat package is documented in four text files:
|
||||
|
||||
SoftFloat.txt Documentation for using the SoftFloat functions.
|
||||
SoftFloat-source.txt Documentation for compiling SoftFloat.
|
||||
SoftFloat-history.txt History of major changes to SoftFloat.
|
||||
timesoftfloat.txt Documentation for using `timesoftfloat'.
|
||||
|
||||
Other files in the package comprise the source code for SoftFloat.
|
||||
|
||||
Please be aware that some work is involved in porting this software to other
|
||||
targets. It is not just a matter of getting `make' to complete without
|
||||
error messages. I would have written the code that way if I could, but
|
||||
there are fundamental differences between systems that can't be hidden.
|
||||
You should not attempt to compile SoftFloat without first reading both
|
||||
`SoftFloat.txt' and `SoftFloat-source.txt'.
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Legal Notice
|
||||
|
||||
SoftFloat was written by me, John R. Hauser. This work was made possible in
|
||||
part by the International Computer Science Institute, located at Suite 600,
|
||||
1947 Center Street, Berkeley, California 94704. Funding was partially
|
||||
provided by the National Science Foundation under grant MIP-9311980. The
|
||||
original version of this code was written as part of a project to build
|
||||
a fixed-point vector processor in collaboration with the University of
|
||||
California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek.
|
||||
|
||||
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
|
||||
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
|
||||
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
|
||||
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL
|
||||
LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO
|
||||
FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER
|
||||
SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES,
|
||||
COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE
|
||||
SOFTWARE.
|
||||
|
||||
Derivative works are acceptable, even for commercial purposes, provided
|
||||
that the minimal documentation requirements stated in the source code are
|
||||
satisfied.
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Contact Information
|
||||
|
||||
At the time of this writing, the most up-to-date information about
|
||||
SoftFloat and the latest release can be found at the Web page `http://
|
||||
www.cs.berkeley.edu/~jhauser/arithmetic/SoftFloat.html'.
|
||||
|
||||
|
||||
MAME note: this package is derived from the following original SoftFloat
|
||||
package and has been "re-packaged" to work with MAME's conventions and
|
||||
build system. The source files come from bits64/ and bits64/templates
|
||||
in the original distribution as MAME requires a compiler with a 64-bit
|
||||
integer type.
|
||||
|
||||
|
||||
Package Overview for SoftFloat Release 2b
|
||||
|
||||
John R. Hauser
|
||||
2002 May 27
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Overview
|
||||
|
||||
SoftFloat is a software implementation of floating-point that conforms to
|
||||
the IEC/IEEE Standard for Binary Floating-Point Arithmetic. SoftFloat is
|
||||
distributed in the form of C source code. Compiling the SoftFloat sources
|
||||
generates two things:
|
||||
|
||||
-- A SoftFloat object file (typically `softfloat.o') containing the complete
|
||||
set of IEC/IEEE floating-point routines.
|
||||
|
||||
-- A `timesoftfloat' program for evaluating the speed of the SoftFloat
|
||||
routines. (The SoftFloat module is linked into this program.)
|
||||
|
||||
The SoftFloat package is documented in four text files:
|
||||
|
||||
SoftFloat.txt Documentation for using the SoftFloat functions.
|
||||
SoftFloat-source.txt Documentation for compiling SoftFloat.
|
||||
SoftFloat-history.txt History of major changes to SoftFloat.
|
||||
timesoftfloat.txt Documentation for using `timesoftfloat'.
|
||||
|
||||
Other files in the package comprise the source code for SoftFloat.
|
||||
|
||||
Please be aware that some work is involved in porting this software to other
|
||||
targets. It is not just a matter of getting `make' to complete without
|
||||
error messages. I would have written the code that way if I could, but
|
||||
there are fundamental differences between systems that can't be hidden.
|
||||
You should not attempt to compile SoftFloat without first reading both
|
||||
`SoftFloat.txt' and `SoftFloat-source.txt'.
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Legal Notice
|
||||
|
||||
SoftFloat was written by me, John R. Hauser. This work was made possible in
|
||||
part by the International Computer Science Institute, located at Suite 600,
|
||||
1947 Center Street, Berkeley, California 94704. Funding was partially
|
||||
provided by the National Science Foundation under grant MIP-9311980. The
|
||||
original version of this code was written as part of a project to build
|
||||
a fixed-point vector processor in collaboration with the University of
|
||||
California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek.
|
||||
|
||||
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
|
||||
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
|
||||
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
|
||||
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL
|
||||
LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO
|
||||
FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER
|
||||
SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES,
|
||||
COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE
|
||||
SOFTWARE.
|
||||
|
||||
Derivative works are acceptable, even for commercial purposes, provided
|
||||
that the minimal documentation requirements stated in the source code are
|
||||
satisfied.
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Contact Information
|
||||
|
||||
At the time of this writing, the most up-to-date information about
|
||||
SoftFloat and the latest release can be found at the Web page `http://
|
||||
www.cs.berkeley.edu/~jhauser/arithmetic/SoftFloat.html'.
|
||||
|
||||
|
||||
|
||||
@@ -1,61 +1,61 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
| One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#ifdef LSB_FIRST
|
||||
#define LITTLEENDIAN
|
||||
#else
|
||||
#define BIGENDIAN
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The macro `BITS64' can be defined to indicate that 64-bit integer types are
|
||||
| supported by the compiler.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define BITS64
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Each of the following `typedef's defines the most convenient type that holds
|
||||
| integers of at least as many bits as specified. For example, `uint8' should
|
||||
| be the most convenient type that can hold unsigned integers of as many as
|
||||
| 8 bits. The `flag' type must be able to hold either a 0 or 1. For most
|
||||
| implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
|
||||
| to the same as `int'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
typedef sint8 flag;
|
||||
typedef sint8 int8;
|
||||
typedef sint16 int16;
|
||||
typedef sint32 int32;
|
||||
typedef sint64 int64;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Each of the following `typedef's defines a type that holds integers
|
||||
| of _exactly_ the number of bits specified. For instance, for most
|
||||
| implementation of C, `bits16' and `sbits16' should be `typedef'ed to
|
||||
| `unsigned short int' and `signed short int' (or `short int'), respectively.
|
||||
*----------------------------------------------------------------------------*/
|
||||
typedef uint8 bits8;
|
||||
typedef sint8 sbits8;
|
||||
typedef uint16 bits16;
|
||||
typedef sint16 sbits16;
|
||||
typedef uint32 bits32;
|
||||
typedef sint32 sbits32;
|
||||
typedef uint64 bits64;
|
||||
typedef sint64 sbits64;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The `LIT64' macro takes as its argument a textual integer literal and
|
||||
| if necessary ``marks'' the literal as having a 64-bit integer type.
|
||||
| For example, the GNU C Compiler (`gcc') requires that 64-bit literals be
|
||||
| appended with the letters `LL' standing for `long long', which is `gcc's
|
||||
| name for the 64-bit integer type. Some compilers may allow `LIT64' to be
|
||||
| defined as the identity macro: `#define LIT64( a ) a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define LIT64( a ) a##ULL
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The macro `INLINE' can be used before functions that should be inlined. If
|
||||
| a compiler does not support explicit inlining, this macro should be defined
|
||||
| to be `static'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
// MAME defines INLINE
|
||||
/*----------------------------------------------------------------------------
|
||||
| One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#ifdef LSB_FIRST
|
||||
#define LITTLEENDIAN
|
||||
#else
|
||||
#define BIGENDIAN
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The macro `BITS64' can be defined to indicate that 64-bit integer types are
|
||||
| supported by the compiler.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define BITS64
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Each of the following `typedef's defines the most convenient type that holds
|
||||
| integers of at least as many bits as specified. For example, `uint8' should
|
||||
| be the most convenient type that can hold unsigned integers of as many as
|
||||
| 8 bits. The `flag' type must be able to hold either a 0 or 1. For most
|
||||
| implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
|
||||
| to the same as `int'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
typedef sint8 flag;
|
||||
typedef sint8 int8;
|
||||
typedef sint16 int16;
|
||||
typedef sint32 int32;
|
||||
typedef sint64 int64;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Each of the following `typedef's defines a type that holds integers
|
||||
| of _exactly_ the number of bits specified. For instance, for most
|
||||
| implementation of C, `bits16' and `sbits16' should be `typedef'ed to
|
||||
| `unsigned short int' and `signed short int' (or `short int'), respectively.
|
||||
*----------------------------------------------------------------------------*/
|
||||
typedef uint8 bits8;
|
||||
typedef sint8 sbits8;
|
||||
typedef uint16 bits16;
|
||||
typedef sint16 sbits16;
|
||||
typedef uint32 bits32;
|
||||
typedef sint32 sbits32;
|
||||
typedef uint64 bits64;
|
||||
typedef sint64 sbits64;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The `LIT64' macro takes as its argument a textual integer literal and
|
||||
| if necessary ``marks'' the literal as having a 64-bit integer type.
|
||||
| For example, the GNU C Compiler (`gcc') requires that 64-bit literals be
|
||||
| appended with the letters `LL' standing for `long long', which is `gcc's
|
||||
| name for the 64-bit integer type. Some compilers may allow `LIT64' to be
|
||||
| defined as the identity macro: `#define LIT64( a ) a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define LIT64( a ) a##ULL
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The macro `INLINE' can be used before functions that should be inlined. If
|
||||
| a compiler does not support explicit inlining, this macro should be defined
|
||||
| to be `static'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
// MAME defines INLINE
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
|
||||
Package, Release 2b.
|
||||
|
||||
Written by John R. Hauser. This work was made possible in part by the
|
||||
International Computer Science Institute, located at Suite 600, 1947 Center
|
||||
Street, Berkeley, California 94704. Funding was partially provided by the
|
||||
National Science Foundation under grant MIP-9311980. The original version
|
||||
of this code was written as part of a project to build a fixed-point vector
|
||||
processor in collaboration with the University of California at Berkeley,
|
||||
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
|
||||
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
|
||||
arithmetic/SoftFloat.html'.
|
||||
|
||||
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
|
||||
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
|
||||
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
|
||||
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
|
||||
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
|
||||
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
|
||||
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
|
||||
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
|
||||
|
||||
Derivative works are acceptable, even for commercial purposes, so long as
|
||||
(1) the source code for the derivative work includes prominent notice that
|
||||
the work is derivative, and (2) the source code includes prominent notice with
|
||||
these four paragraphs for those parts of this code that are retained.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Include common integer types and flags.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#include "mamesf.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Symbolic Boolean literals.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
|
||||
Package, Release 2b.
|
||||
|
||||
Written by John R. Hauser. This work was made possible in part by the
|
||||
International Computer Science Institute, located at Suite 600, 1947 Center
|
||||
Street, Berkeley, California 94704. Funding was partially provided by the
|
||||
National Science Foundation under grant MIP-9311980. The original version
|
||||
of this code was written as part of a project to build a fixed-point vector
|
||||
processor in collaboration with the University of California at Berkeley,
|
||||
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
|
||||
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
|
||||
arithmetic/SoftFloat.html'.
|
||||
|
||||
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
|
||||
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
|
||||
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
|
||||
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
|
||||
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
|
||||
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
|
||||
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
|
||||
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
|
||||
|
||||
Derivative works are acceptable, even for commercial purposes, so long as
|
||||
(1) the source code for the derivative work includes prominent notice that
|
||||
the work is derivative, and (2) the source code includes prominent notice with
|
||||
these four paragraphs for those parts of this code that are retained.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Include common integer types and flags.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#include "mamesf.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Symbolic Boolean literals.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,476 +1,476 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
|
||||
Arithmetic Package, Release 2b.
|
||||
|
||||
Written by John R. Hauser. This work was made possible in part by the
|
||||
International Computer Science Institute, located at Suite 600, 1947 Center
|
||||
Street, Berkeley, California 94704. Funding was partially provided by the
|
||||
National Science Foundation under grant MIP-9311980. The original version
|
||||
of this code was written as part of a project to build a fixed-point vector
|
||||
processor in collaboration with the University of California at Berkeley,
|
||||
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
|
||||
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
|
||||
arithmetic/SoftFloat.html'.
|
||||
|
||||
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
|
||||
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
|
||||
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
|
||||
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
|
||||
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
|
||||
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
|
||||
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
|
||||
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
|
||||
|
||||
Derivative works are acceptable, even for commercial purposes, so long as
|
||||
(1) the source code for the derivative work includes prominent notice that
|
||||
the work is derivative, and (2) the source code includes prominent notice with
|
||||
these four paragraphs for those parts of this code that are retained.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
flag float32_is_nan( float32 a );
|
||||
flag float64_is_nan( float64 a );
|
||||
flag floatx80_is_nan( floatx80 a );
|
||||
floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b );
|
||||
flag float128_is_nan( float128 a );
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Underflow tininess-detection mode, statically initialized to default value.
|
||||
| (The declaration in `softfloat.h' must match the `int8' type here.)
|
||||
*----------------------------------------------------------------------------*/
|
||||
int8 float_detect_tininess = float_tininess_after_rounding;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Raises the exceptions specified by `flags'. Floating-point traps can be
|
||||
| defined here if desired. It is currently not possible for such a trap to
|
||||
| substitute a result value. If traps are not implemented, this routine
|
||||
| should be simply `float_exception_flags |= flags;'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
void float_raise( int8 flags )
|
||||
{
|
||||
|
||||
float_exception_flags |= flags;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Internal canonical NaN format.
|
||||
*----------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
flag sign;
|
||||
bits64 high, low;
|
||||
} commonNaNT;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The pattern for a default generated single-precision NaN.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define float32_default_nan 0xFFFFFFFF
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the single-precision floating-point value `a' is a NaN;
|
||||
| otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float32_is_nan( float32 a )
|
||||
{
|
||||
|
||||
return ( 0xFF000000 < (bits32) ( a<<1 ) );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the single-precision floating-point value `a' is a signaling
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float32_is_signaling_nan( float32 a )
|
||||
{
|
||||
|
||||
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the single-precision floating-point NaN
|
||||
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static commonNaNT float32ToCommonNaN( float32 a )
|
||||
{
|
||||
commonNaNT z;
|
||||
|
||||
if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
|
||||
z.sign = a>>31;
|
||||
z.low = 0;
|
||||
z.high = ( (bits64) a )<<41;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the canonical NaN `a' to the single-
|
||||
| precision floating-point format.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float32 commonNaNToFloat32( commonNaNT a )
|
||||
{
|
||||
|
||||
return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Takes two single-precision floating-point values `a' and `b', one of which
|
||||
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
|
||||
| signaling NaN, the invalid exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float32 propagateFloat32NaN( float32 a, float32 b )
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
|
||||
aIsNaN = float32_is_nan( a );
|
||||
aIsSignalingNaN = float32_is_signaling_nan( a );
|
||||
bIsNaN = float32_is_nan( b );
|
||||
bIsSignalingNaN = float32_is_signaling_nan( b );
|
||||
a |= 0x00400000;
|
||||
b |= 0x00400000;
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
|
||||
if ( aIsNaN ) {
|
||||
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
|
||||
}
|
||||
else {
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The pattern for a default generated double-precision NaN.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF )
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the double-precision floating-point value `a' is a NaN;
|
||||
| otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float64_is_nan( float64 a )
|
||||
{
|
||||
|
||||
return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the double-precision floating-point value `a' is a signaling
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float64_is_signaling_nan( float64 a )
|
||||
{
|
||||
|
||||
return
|
||||
( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
|
||||
&& ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the double-precision floating-point NaN
|
||||
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static commonNaNT float64ToCommonNaN( float64 a )
|
||||
{
|
||||
commonNaNT z;
|
||||
|
||||
if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
|
||||
z.sign = a>>63;
|
||||
z.low = 0;
|
||||
z.high = a<<12;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the canonical NaN `a' to the double-
|
||||
| precision floating-point format.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float64 commonNaNToFloat64( commonNaNT a )
|
||||
{
|
||||
|
||||
return
|
||||
( ( (bits64) a.sign )<<63 )
|
||||
| LIT64( 0x7FF8000000000000 )
|
||||
| ( a.high>>12 );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Takes two double-precision floating-point values `a' and `b', one of which
|
||||
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
|
||||
| signaling NaN, the invalid exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float64 propagateFloat64NaN( float64 a, float64 b )
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
|
||||
aIsNaN = float64_is_nan( a );
|
||||
aIsSignalingNaN = float64_is_signaling_nan( a );
|
||||
bIsNaN = float64_is_nan( b );
|
||||
bIsSignalingNaN = float64_is_signaling_nan( b );
|
||||
a |= LIT64( 0x0008000000000000 );
|
||||
b |= LIT64( 0x0008000000000000 );
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
|
||||
if ( aIsNaN ) {
|
||||
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
|
||||
}
|
||||
else {
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef FLOATX80
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The pattern for a default generated extended double-precision NaN. The
|
||||
| `high' and `low' values hold the most- and least-significant bits,
|
||||
| respectively.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define floatx80_default_nan_high 0xFFFF
|
||||
#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the extended double-precision floating-point value `a' is a
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag floatx80_is_nan( floatx80 a )
|
||||
{
|
||||
|
||||
return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the extended double-precision floating-point value `a' is a
|
||||
| signaling NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag floatx80_is_signaling_nan( floatx80 a )
|
||||
{
|
||||
bits64 aLow;
|
||||
|
||||
aLow = a.low & ~ LIT64( 0x4000000000000000 );
|
||||
return
|
||||
( ( a.high & 0x7FFF ) == 0x7FFF )
|
||||
&& (bits64) ( aLow<<1 )
|
||||
&& ( a.low == aLow );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the extended double-precision floating-
|
||||
| point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
|
||||
| invalid exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static commonNaNT floatx80ToCommonNaN( floatx80 a )
|
||||
{
|
||||
commonNaNT z;
|
||||
|
||||
if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
|
||||
z.sign = a.high>>15;
|
||||
z.low = 0;
|
||||
z.high = a.low<<1;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the canonical NaN `a' to the extended
|
||||
| double-precision floating-point format.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static floatx80 commonNaNToFloatx80( commonNaNT a )
|
||||
{
|
||||
floatx80 z;
|
||||
|
||||
z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
|
||||
z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Takes two extended double-precision floating-point values `a' and `b', one
|
||||
| of which is a NaN, and returns the appropriate NaN result. If either `a' or
|
||||
| `b' is a signaling NaN, the invalid exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b )
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
|
||||
aIsNaN = floatx80_is_nan( a );
|
||||
aIsSignalingNaN = floatx80_is_signaling_nan( a );
|
||||
bIsNaN = floatx80_is_nan( b );
|
||||
bIsSignalingNaN = floatx80_is_signaling_nan( b );
|
||||
a.low |= LIT64( 0xC000000000000000 );
|
||||
b.low |= LIT64( 0xC000000000000000 );
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
|
||||
if ( aIsNaN ) {
|
||||
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
|
||||
}
|
||||
else {
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define EXP_BIAS 0x3FFF
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the fraction bits of the extended double-precision floating-point
|
||||
| value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline bits64 extractFloatx80Frac( floatx80 a )
|
||||
{
|
||||
|
||||
return a.low;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the exponent bits of the extended double-precision floating-point
|
||||
| value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline int32 extractFloatx80Exp( floatx80 a )
|
||||
{
|
||||
|
||||
return a.high & 0x7FFF;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the sign bit of the extended double-precision floating-point value
|
||||
| `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline flag extractFloatx80Sign( floatx80 a )
|
||||
{
|
||||
|
||||
return a.high>>15;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FLOAT128
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The pattern for a default generated quadruple-precision NaN. The `high' and
|
||||
| `low' values hold the most- and least-significant bits, respectively.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF )
|
||||
#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
|
||||
| otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float128_is_nan( float128 a )
|
||||
{
|
||||
|
||||
return
|
||||
( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
|
||||
&& ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the quadruple-precision floating-point value `a' is a
|
||||
| signaling NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float128_is_signaling_nan( float128 a )
|
||||
{
|
||||
|
||||
return
|
||||
( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
|
||||
&& ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the quadruple-precision floating-point NaN
|
||||
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static commonNaNT float128ToCommonNaN( float128 a )
|
||||
{
|
||||
commonNaNT z;
|
||||
|
||||
if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
|
||||
z.sign = a.high>>63;
|
||||
shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the canonical NaN `a' to the quadruple-
|
||||
| precision floating-point format.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float128 commonNaNToFloat128( commonNaNT a )
|
||||
{
|
||||
float128 z;
|
||||
|
||||
shift128Right( a.high, a.low, 16, &z.high, &z.low );
|
||||
z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Takes two quadruple-precision floating-point values `a' and `b', one of
|
||||
| which is a NaN, and returns the appropriate NaN result. If either `a' or
|
||||
| `b' is a signaling NaN, the invalid exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float128 propagateFloat128NaN( float128 a, float128 b )
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
|
||||
aIsNaN = float128_is_nan( a );
|
||||
aIsSignalingNaN = float128_is_signaling_nan( a );
|
||||
bIsNaN = float128_is_nan( b );
|
||||
bIsSignalingNaN = float128_is_signaling_nan( b );
|
||||
a.high |= LIT64( 0x0000800000000000 );
|
||||
b.high |= LIT64( 0x0000800000000000 );
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
|
||||
if ( aIsNaN ) {
|
||||
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
|
||||
}
|
||||
else {
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
|
||||
Arithmetic Package, Release 2b.
|
||||
|
||||
Written by John R. Hauser. This work was made possible in part by the
|
||||
International Computer Science Institute, located at Suite 600, 1947 Center
|
||||
Street, Berkeley, California 94704. Funding was partially provided by the
|
||||
National Science Foundation under grant MIP-9311980. The original version
|
||||
of this code was written as part of a project to build a fixed-point vector
|
||||
processor in collaboration with the University of California at Berkeley,
|
||||
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
|
||||
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
|
||||
arithmetic/SoftFloat.html'.
|
||||
|
||||
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
|
||||
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
|
||||
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
|
||||
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
|
||||
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
|
||||
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
|
||||
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
|
||||
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
|
||||
|
||||
Derivative works are acceptable, even for commercial purposes, so long as
|
||||
(1) the source code for the derivative work includes prominent notice that
|
||||
the work is derivative, and (2) the source code includes prominent notice with
|
||||
these four paragraphs for those parts of this code that are retained.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
flag float32_is_nan( float32 a );
|
||||
flag float64_is_nan( float64 a );
|
||||
flag floatx80_is_nan( floatx80 a );
|
||||
floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b );
|
||||
flag float128_is_nan( float128 a );
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Underflow tininess-detection mode, statically initialized to default value.
|
||||
| (The declaration in `softfloat.h' must match the `int8' type here.)
|
||||
*----------------------------------------------------------------------------*/
|
||||
int8 float_detect_tininess = float_tininess_after_rounding;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Raises the exceptions specified by `flags'. Floating-point traps can be
|
||||
| defined here if desired. It is currently not possible for such a trap to
|
||||
| substitute a result value. If traps are not implemented, this routine
|
||||
| should be simply `float_exception_flags |= flags;'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
void float_raise( int8 flags )
|
||||
{
|
||||
|
||||
float_exception_flags |= flags;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Internal canonical NaN format.
|
||||
*----------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
flag sign;
|
||||
bits64 high, low;
|
||||
} commonNaNT;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The pattern for a default generated single-precision NaN.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define float32_default_nan 0xFFFFFFFF
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the single-precision floating-point value `a' is a NaN;
|
||||
| otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float32_is_nan( float32 a )
|
||||
{
|
||||
|
||||
return ( 0xFF000000 < (bits32) ( a<<1 ) );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the single-precision floating-point value `a' is a signaling
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float32_is_signaling_nan( float32 a )
|
||||
{
|
||||
|
||||
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the single-precision floating-point NaN
|
||||
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static commonNaNT float32ToCommonNaN( float32 a )
|
||||
{
|
||||
commonNaNT z;
|
||||
|
||||
if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
|
||||
z.sign = a>>31;
|
||||
z.low = 0;
|
||||
z.high = ( (bits64) a )<<41;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the canonical NaN `a' to the single-
|
||||
| precision floating-point format.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float32 commonNaNToFloat32( commonNaNT a )
|
||||
{
|
||||
|
||||
return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Takes two single-precision floating-point values `a' and `b', one of which
|
||||
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
|
||||
| signaling NaN, the invalid exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float32 propagateFloat32NaN( float32 a, float32 b )
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
|
||||
aIsNaN = float32_is_nan( a );
|
||||
aIsSignalingNaN = float32_is_signaling_nan( a );
|
||||
bIsNaN = float32_is_nan( b );
|
||||
bIsSignalingNaN = float32_is_signaling_nan( b );
|
||||
a |= 0x00400000;
|
||||
b |= 0x00400000;
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
|
||||
if ( aIsNaN ) {
|
||||
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
|
||||
}
|
||||
else {
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The pattern for a default generated double-precision NaN.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF )
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the double-precision floating-point value `a' is a NaN;
|
||||
| otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float64_is_nan( float64 a )
|
||||
{
|
||||
|
||||
return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the double-precision floating-point value `a' is a signaling
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float64_is_signaling_nan( float64 a )
|
||||
{
|
||||
|
||||
return
|
||||
( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
|
||||
&& ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the double-precision floating-point NaN
|
||||
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static commonNaNT float64ToCommonNaN( float64 a )
|
||||
{
|
||||
commonNaNT z;
|
||||
|
||||
if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
|
||||
z.sign = a>>63;
|
||||
z.low = 0;
|
||||
z.high = a<<12;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the canonical NaN `a' to the double-
|
||||
| precision floating-point format.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float64 commonNaNToFloat64( commonNaNT a )
|
||||
{
|
||||
|
||||
return
|
||||
( ( (bits64) a.sign )<<63 )
|
||||
| LIT64( 0x7FF8000000000000 )
|
||||
| ( a.high>>12 );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Takes two double-precision floating-point values `a' and `b', one of which
|
||||
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
|
||||
| signaling NaN, the invalid exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float64 propagateFloat64NaN( float64 a, float64 b )
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
|
||||
aIsNaN = float64_is_nan( a );
|
||||
aIsSignalingNaN = float64_is_signaling_nan( a );
|
||||
bIsNaN = float64_is_nan( b );
|
||||
bIsSignalingNaN = float64_is_signaling_nan( b );
|
||||
a |= LIT64( 0x0008000000000000 );
|
||||
b |= LIT64( 0x0008000000000000 );
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
|
||||
if ( aIsNaN ) {
|
||||
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
|
||||
}
|
||||
else {
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef FLOATX80
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The pattern for a default generated extended double-precision NaN. The
|
||||
| `high' and `low' values hold the most- and least-significant bits,
|
||||
| respectively.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define floatx80_default_nan_high 0xFFFF
|
||||
#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the extended double-precision floating-point value `a' is a
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag floatx80_is_nan( floatx80 a )
|
||||
{
|
||||
|
||||
return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the extended double-precision floating-point value `a' is a
|
||||
| signaling NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag floatx80_is_signaling_nan( floatx80 a )
|
||||
{
|
||||
bits64 aLow;
|
||||
|
||||
aLow = a.low & ~ LIT64( 0x4000000000000000 );
|
||||
return
|
||||
( ( a.high & 0x7FFF ) == 0x7FFF )
|
||||
&& (bits64) ( aLow<<1 )
|
||||
&& ( a.low == aLow );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the extended double-precision floating-
|
||||
| point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
|
||||
| invalid exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static commonNaNT floatx80ToCommonNaN( floatx80 a )
|
||||
{
|
||||
commonNaNT z;
|
||||
|
||||
if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
|
||||
z.sign = a.high>>15;
|
||||
z.low = 0;
|
||||
z.high = a.low<<1;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the canonical NaN `a' to the extended
|
||||
| double-precision floating-point format.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static floatx80 commonNaNToFloatx80( commonNaNT a )
|
||||
{
|
||||
floatx80 z;
|
||||
|
||||
z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
|
||||
z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Takes two extended double-precision floating-point values `a' and `b', one
|
||||
| of which is a NaN, and returns the appropriate NaN result. If either `a' or
|
||||
| `b' is a signaling NaN, the invalid exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b )
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
|
||||
aIsNaN = floatx80_is_nan( a );
|
||||
aIsSignalingNaN = floatx80_is_signaling_nan( a );
|
||||
bIsNaN = floatx80_is_nan( b );
|
||||
bIsSignalingNaN = floatx80_is_signaling_nan( b );
|
||||
a.low |= LIT64( 0xC000000000000000 );
|
||||
b.low |= LIT64( 0xC000000000000000 );
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
|
||||
if ( aIsNaN ) {
|
||||
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
|
||||
}
|
||||
else {
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define EXP_BIAS 0x3FFF
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the fraction bits of the extended double-precision floating-point
|
||||
| value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline bits64 extractFloatx80Frac( floatx80 a )
|
||||
{
|
||||
|
||||
return a.low;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the exponent bits of the extended double-precision floating-point
|
||||
| value `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline int32 extractFloatx80Exp( floatx80 a )
|
||||
{
|
||||
|
||||
return a.high & 0x7FFF;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the sign bit of the extended double-precision floating-point value
|
||||
| `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline flag extractFloatx80Sign( floatx80 a )
|
||||
{
|
||||
|
||||
return a.high>>15;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FLOAT128
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The pattern for a default generated quadruple-precision NaN. The `high' and
|
||||
| `low' values hold the most- and least-significant bits, respectively.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF )
|
||||
#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
|
||||
| otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float128_is_nan( float128 a )
|
||||
{
|
||||
|
||||
return
|
||||
( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
|
||||
&& ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns 1 if the quadruple-precision floating-point value `a' is a
|
||||
| signaling NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
flag float128_is_signaling_nan( float128 a )
|
||||
{
|
||||
|
||||
return
|
||||
( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
|
||||
&& ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the quadruple-precision floating-point NaN
|
||||
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
|
||||
| exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static commonNaNT float128ToCommonNaN( float128 a )
|
||||
{
|
||||
commonNaNT z;
|
||||
|
||||
if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
|
||||
z.sign = a.high>>63;
|
||||
shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the canonical NaN `a' to the quadruple-
|
||||
| precision floating-point format.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float128 commonNaNToFloat128( commonNaNT a )
|
||||
{
|
||||
float128 z;
|
||||
|
||||
shift128Right( a.high, a.low, 16, &z.high, &z.low );
|
||||
z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Takes two quadruple-precision floating-point values `a' and `b', one of
|
||||
| which is a NaN, and returns the appropriate NaN result. If either `a' or
|
||||
| `b' is a signaling NaN, the invalid exception is raised.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static float128 propagateFloat128NaN( float128 a, float128 b )
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
|
||||
aIsNaN = float128_is_nan( a );
|
||||
aIsSignalingNaN = float128_is_signaling_nan( a );
|
||||
bIsNaN = float128_is_nan( b );
|
||||
bIsSignalingNaN = float128_is_signaling_nan( b );
|
||||
a.high |= LIT64( 0x0000800000000000 );
|
||||
b.high |= LIT64( 0x0000800000000000 );
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
|
||||
if ( aIsNaN ) {
|
||||
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
|
||||
}
|
||||
else {
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,460 +1,460 @@
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
|
||||
Package, Release 2b.
|
||||
|
||||
Written by John R. Hauser. This work was made possible in part by the
|
||||
International Computer Science Institute, located at Suite 600, 1947 Center
|
||||
Street, Berkeley, California 94704. Funding was partially provided by the
|
||||
National Science Foundation under grant MIP-9311980. The original version
|
||||
of this code was written as part of a project to build a fixed-point vector
|
||||
processor in collaboration with the University of California at Berkeley,
|
||||
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
|
||||
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
|
||||
arithmetic/SoftFloat.html'.
|
||||
|
||||
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
|
||||
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
|
||||
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
|
||||
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
|
||||
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
|
||||
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
|
||||
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
|
||||
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
|
||||
|
||||
Derivative works are acceptable, even for commercial purposes, so long as
|
||||
(1) the source code for the derivative work includes prominent notice that
|
||||
the work is derivative, and (2) the source code includes prominent notice with
|
||||
these four paragraphs for those parts of this code that are retained.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The macro `FLOATX80' must be defined to enable the extended double-precision
|
||||
| floating-point format `floatx80'. If this macro is not defined, the
|
||||
| `floatx80' type will not be defined, and none of the functions that either
|
||||
| input or output the `floatx80' type will be defined. The same applies to
|
||||
| the `FLOAT128' macro and the quadruple-precision format `float128'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define FLOATX80
|
||||
#define FLOAT128
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE floating-point types.
|
||||
*----------------------------------------------------------------------------*/
|
||||
typedef bits32 float32;
|
||||
typedef bits64 float64;
|
||||
#ifdef FLOATX80
|
||||
typedef struct {
|
||||
bits16 high;
|
||||
bits64 low;
|
||||
} floatx80;
|
||||
#endif
|
||||
#ifdef FLOAT128
|
||||
typedef struct {
|
||||
bits64 high, low;
|
||||
} float128;
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Primitive arithmetic functions, including multi-word arithmetic, and
|
||||
| division and square root approximations. (Can be specialized to target if
|
||||
| desired.)
|
||||
*----------------------------------------------------------------------------*/
|
||||
#include "softfloat-macros"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE floating-point underflow tininess-detection mode.
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern int8 float_detect_tininess;
|
||||
enum {
|
||||
float_tininess_after_rounding = 0,
|
||||
float_tininess_before_rounding = 1
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE floating-point rounding mode.
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern int8 float_rounding_mode;
|
||||
enum {
|
||||
float_round_nearest_even = 0,
|
||||
float_round_to_zero = 1,
|
||||
float_round_down = 2,
|
||||
float_round_up = 3
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE floating-point exception flags.
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern int8 float_exception_flags;
|
||||
enum {
|
||||
float_flag_invalid = 0x01, float_flag_denormal = 0x02, float_flag_divbyzero = 0x04, float_flag_overflow = 0x08,
|
||||
float_flag_underflow = 0x10, float_flag_inexact = 0x20
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Routine to raise any or all of the software IEC/IEEE floating-point
|
||||
| exception flags.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void float_raise( int8 );
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE integer-to-floating-point conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float32 int32_to_float32( int32 );
|
||||
float64 int32_to_float64( int32 );
|
||||
#ifdef FLOATX80
|
||||
floatx80 int32_to_floatx80( int32 );
|
||||
#endif
|
||||
#ifdef FLOAT128
|
||||
float128 int32_to_float128( int32 );
|
||||
#endif
|
||||
float32 int64_to_float32( int64 );
|
||||
float64 int64_to_float64( int64 );
|
||||
#ifdef FLOATX80
|
||||
floatx80 int64_to_floatx80( int64 );
|
||||
#endif
|
||||
#ifdef FLOAT128
|
||||
float128 int64_to_float128( int64 );
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE single-precision conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
int32 float32_to_int32( float32 );
|
||||
int32 float32_to_int32_round_to_zero( float32 );
|
||||
int64 float32_to_int64( float32 );
|
||||
int64 float32_to_int64_round_to_zero( float32 );
|
||||
float64 float32_to_float64( float32 );
|
||||
#ifdef FLOATX80
|
||||
floatx80 float32_to_floatx80( float32 );
|
||||
#endif
|
||||
#ifdef FLOAT128
|
||||
float128 float32_to_float128( float32 );
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE single-precision operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float32 float32_round_to_int( float32 );
|
||||
float32 float32_add( float32, float32 );
|
||||
float32 float32_sub( float32, float32 );
|
||||
float32 float32_mul( float32, float32 );
|
||||
float32 float32_div( float32, float32 );
|
||||
float32 float32_rem( float32, float32 );
|
||||
float32 float32_sqrt( float32 );
|
||||
flag float32_eq( float32, float32 );
|
||||
flag float32_le( float32, float32 );
|
||||
flag float32_lt( float32, float32 );
|
||||
flag float32_eq_signaling( float32, float32 );
|
||||
flag float32_le_quiet( float32, float32 );
|
||||
flag float32_lt_quiet( float32, float32 );
|
||||
flag float32_is_signaling_nan( float32 );
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE double-precision conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
int32 float64_to_int32( float64 );
|
||||
int32 float64_to_int32_round_to_zero( float64 );
|
||||
int64 float64_to_int64( float64 );
|
||||
int64 float64_to_int64_round_to_zero( float64 );
|
||||
float32 float64_to_float32( float64 );
|
||||
#ifdef FLOATX80
|
||||
floatx80 float64_to_floatx80( float64 );
|
||||
#endif
|
||||
#ifdef FLOAT128
|
||||
float128 float64_to_float128( float64 );
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE double-precision operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float64 float64_round_to_int( float64 );
|
||||
float64 float64_add( float64, float64 );
|
||||
float64 float64_sub( float64, float64 );
|
||||
float64 float64_mul( float64, float64 );
|
||||
float64 float64_div( float64, float64 );
|
||||
float64 float64_rem( float64, float64 );
|
||||
float64 float64_sqrt( float64 );
|
||||
flag float64_eq( float64, float64 );
|
||||
flag float64_le( float64, float64 );
|
||||
flag float64_lt( float64, float64 );
|
||||
flag float64_eq_signaling( float64, float64 );
|
||||
flag float64_le_quiet( float64, float64 );
|
||||
flag float64_lt_quiet( float64, float64 );
|
||||
flag float64_is_signaling_nan( float64 );
|
||||
|
||||
#ifdef FLOATX80
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE extended double-precision conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
int32 floatx80_to_int32( floatx80 );
|
||||
int32 floatx80_to_int32_round_to_zero( floatx80 );
|
||||
int64 floatx80_to_int64( floatx80 );
|
||||
int64 floatx80_to_int64_round_to_zero( floatx80 );
|
||||
float32 floatx80_to_float32( floatx80 );
|
||||
float64 floatx80_to_float64( floatx80 );
|
||||
#ifdef FLOAT128
|
||||
float128 floatx80_to_float128( floatx80 );
|
||||
#endif
|
||||
floatx80 floatx80_scale(floatx80 a, floatx80 b);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Packs the sign `zSign', exponent `zExp', and significand `zSig' into an
|
||||
| extended double-precision floating-point value, returning the result.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline floatx80 packFloatx80( flag zSign, int32 zExp, bits64 zSig )
|
||||
{
|
||||
floatx80 z;
|
||||
|
||||
z.low = zSig;
|
||||
z.high = ( ( (bits16) zSign )<<15 ) + zExp;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE extended double-precision rounding precision. Valid
|
||||
| values are 32, 64, and 80.
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern int8 floatx80_rounding_precision;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE extended double-precision operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
floatx80 floatx80_round_to_int( floatx80 );
|
||||
floatx80 floatx80_add( floatx80, floatx80 );
|
||||
floatx80 floatx80_sub( floatx80, floatx80 );
|
||||
floatx80 floatx80_mul( floatx80, floatx80 );
|
||||
floatx80 floatx80_div( floatx80, floatx80 );
|
||||
floatx80 floatx80_rem( floatx80, floatx80 );
|
||||
floatx80 floatx80_sqrt( floatx80 );
|
||||
flag floatx80_eq( floatx80, floatx80 );
|
||||
flag floatx80_le( floatx80, floatx80 );
|
||||
flag floatx80_lt( floatx80, floatx80 );
|
||||
flag floatx80_eq_signaling( floatx80, floatx80 );
|
||||
flag floatx80_le_quiet( floatx80, floatx80 );
|
||||
flag floatx80_lt_quiet( floatx80, floatx80 );
|
||||
flag floatx80_is_signaling_nan( floatx80 );
|
||||
|
||||
/* int floatx80_fsin(floatx80 &a);
|
||||
int floatx80_fcos(floatx80 &a);
|
||||
int floatx80_ftan(floatx80 &a); */
|
||||
|
||||
floatx80 floatx80_flognp1(floatx80 a);
|
||||
floatx80 floatx80_flogn(floatx80 a);
|
||||
floatx80 floatx80_flog2(floatx80 a);
|
||||
floatx80 floatx80_flog10(floatx80 a);
|
||||
|
||||
// roundAndPackFloatx80 used to be in softfloat-round-pack, is now in softfloat.c
|
||||
floatx80 roundAndPackFloatx80(int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FLOAT128
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE quadruple-precision conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
int32 float128_to_int32( float128 );
|
||||
int32 float128_to_int32_round_to_zero( float128 );
|
||||
int64 float128_to_int64( float128 );
|
||||
int64 float128_to_int64_round_to_zero( float128 );
|
||||
float32 float128_to_float32( float128 );
|
||||
float64 float128_to_float64( float128 );
|
||||
#ifdef FLOATX80
|
||||
floatx80 float128_to_floatx80( float128 );
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE quadruple-precision operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float128 float128_round_to_int( float128 );
|
||||
float128 float128_add( float128, float128 );
|
||||
float128 float128_sub( float128, float128 );
|
||||
float128 float128_mul( float128, float128 );
|
||||
float128 float128_div( float128, float128 );
|
||||
float128 float128_rem( float128, float128 );
|
||||
float128 float128_sqrt( float128 );
|
||||
flag float128_eq( float128, float128 );
|
||||
flag float128_le( float128, float128 );
|
||||
flag float128_lt( float128, float128 );
|
||||
flag float128_eq_signaling( float128, float128 );
|
||||
flag float128_le_quiet( float128, float128 );
|
||||
flag float128_lt_quiet( float128, float128 );
|
||||
flag float128_is_signaling_nan( float128 );
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Packs the sign `zSign', the exponent `zExp', and the significand formed
|
||||
| by the concatenation of `zSig0' and `zSig1' into a quadruple-precision
|
||||
| floating-point value, returning the result. After being shifted into the
|
||||
| proper positions, the three fields `zSign', `zExp', and `zSig0' are simply
|
||||
| added together to form the most significant 32 bits of the result. This
|
||||
| means that any integer portion of `zSig0' will be added into the exponent.
|
||||
| Since a properly normalized significand will have an integer portion equal
|
||||
| to 1, the `zExp' input should be 1 less than the desired result exponent
|
||||
| whenever `zSig0' and `zSig1' concatenated form a complete, normalized
|
||||
| significand.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline float128
|
||||
packFloat128( flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
|
||||
{
|
||||
float128 z;
|
||||
|
||||
z.low = zSig1;
|
||||
z.high = ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<48 ) + zSig0;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
|
||||
| and extended significand formed by the concatenation of `zSig0', `zSig1',
|
||||
| and `zSig2', and returns the proper quadruple-precision floating-point value
|
||||
| corresponding to the abstract input. Ordinarily, the abstract value is
|
||||
| simply rounded and packed into the quadruple-precision format, with the
|
||||
| inexact exception raised if the abstract input cannot be represented
|
||||
| exactly. However, if the abstract value is too large, the overflow and
|
||||
| inexact exceptions are raised and an infinity or maximal finite value is
|
||||
| returned. If the abstract value is too small, the input value is rounded to
|
||||
| a subnormal number, and the underflow and inexact exceptions are raised if
|
||||
| the abstract input cannot be represented exactly as a subnormal quadruple-
|
||||
| precision floating-point number.
|
||||
| The input significand must be normalized or smaller. If the input
|
||||
| significand is not normalized, `zExp' must be 0; in that case, the result
|
||||
| returned is a subnormal number, and it must not require rounding. In the
|
||||
| usual case that the input significand is normalized, `zExp' must be 1 less
|
||||
| than the ``true'' floating-point exponent. The handling of underflow and
|
||||
| overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline float128
|
||||
roundAndPackFloat128(
|
||||
flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1, bits64 zSig2 )
|
||||
{
|
||||
int8 roundingMode;
|
||||
flag roundNearestEven, increment, isTiny;
|
||||
|
||||
roundingMode = float_rounding_mode;
|
||||
roundNearestEven = ( roundingMode == float_round_nearest_even );
|
||||
increment = ( (sbits64) zSig2 < 0 );
|
||||
if ( ! roundNearestEven ) {
|
||||
if ( roundingMode == float_round_to_zero ) {
|
||||
increment = 0;
|
||||
}
|
||||
else {
|
||||
if ( zSign ) {
|
||||
increment = ( roundingMode == float_round_down ) && zSig2;
|
||||
}
|
||||
else {
|
||||
increment = ( roundingMode == float_round_up ) && zSig2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( 0x7FFD <= (bits32) zExp ) {
|
||||
if ( ( 0x7FFD < zExp )
|
||||
|| ( ( zExp == 0x7FFD )
|
||||
&& eq128(
|
||||
LIT64( 0x0001FFFFFFFFFFFF ),
|
||||
LIT64( 0xFFFFFFFFFFFFFFFF ),
|
||||
zSig0,
|
||||
zSig1
|
||||
)
|
||||
&& increment
|
||||
)
|
||||
) {
|
||||
float_raise( float_flag_overflow | float_flag_inexact );
|
||||
if ( ( roundingMode == float_round_to_zero )
|
||||
|| ( zSign && ( roundingMode == float_round_up ) )
|
||||
|| ( ! zSign && ( roundingMode == float_round_down ) )
|
||||
) {
|
||||
return
|
||||
packFloat128(
|
||||
zSign,
|
||||
0x7FFE,
|
||||
LIT64( 0x0000FFFFFFFFFFFF ),
|
||||
LIT64( 0xFFFFFFFFFFFFFFFF )
|
||||
);
|
||||
}
|
||||
return packFloat128( zSign, 0x7FFF, 0, 0 );
|
||||
}
|
||||
if ( zExp < 0 ) {
|
||||
isTiny =
|
||||
( float_detect_tininess == float_tininess_before_rounding )
|
||||
|| ( zExp < -1 )
|
||||
|| ! increment
|
||||
|| lt128(
|
||||
zSig0,
|
||||
zSig1,
|
||||
LIT64( 0x0001FFFFFFFFFFFF ),
|
||||
LIT64( 0xFFFFFFFFFFFFFFFF )
|
||||
);
|
||||
shift128ExtraRightJamming(
|
||||
zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 );
|
||||
zExp = 0;
|
||||
if ( isTiny && zSig2 ) float_raise( float_flag_underflow );
|
||||
if ( roundNearestEven ) {
|
||||
increment = ( (sbits64) zSig2 < 0 );
|
||||
}
|
||||
else {
|
||||
if ( zSign ) {
|
||||
increment = ( roundingMode == float_round_down ) && zSig2;
|
||||
}
|
||||
else {
|
||||
increment = ( roundingMode == float_round_up ) && zSig2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( zSig2 ) float_exception_flags |= float_flag_inexact;
|
||||
if ( increment ) {
|
||||
add128( zSig0, zSig1, 0, 1, &zSig0, &zSig1 );
|
||||
zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven );
|
||||
}
|
||||
else {
|
||||
if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0;
|
||||
}
|
||||
return packFloat128( zSign, zExp, zSig0, zSig1 );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
|
||||
| and significand formed by the concatenation of `zSig0' and `zSig1', and
|
||||
| returns the proper quadruple-precision floating-point value corresponding
|
||||
| to the abstract input. This routine is just like `roundAndPackFloat128'
|
||||
| except that the input significand has fewer bits and does not have to be
|
||||
| normalized. In all cases, `zExp' must be 1 less than the ``true'' floating-
|
||||
| point exponent.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline float128
|
||||
normalizeRoundAndPackFloat128(
|
||||
flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
|
||||
{
|
||||
int8 shiftCount;
|
||||
bits64 zSig2;
|
||||
|
||||
if ( zSig0 == 0 ) {
|
||||
zSig0 = zSig1;
|
||||
zSig1 = 0;
|
||||
zExp -= 64;
|
||||
}
|
||||
shiftCount = countLeadingZeros64( zSig0 ) - 15;
|
||||
if ( 0 <= shiftCount ) {
|
||||
zSig2 = 0;
|
||||
shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
|
||||
}
|
||||
else {
|
||||
shift128ExtraRightJamming(
|
||||
zSig0, zSig1, 0, - shiftCount, &zSig0, &zSig1, &zSig2 );
|
||||
}
|
||||
zExp -= shiftCount;
|
||||
return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/*============================================================================
|
||||
|
||||
This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
|
||||
Package, Release 2b.
|
||||
|
||||
Written by John R. Hauser. This work was made possible in part by the
|
||||
International Computer Science Institute, located at Suite 600, 1947 Center
|
||||
Street, Berkeley, California 94704. Funding was partially provided by the
|
||||
National Science Foundation under grant MIP-9311980. The original version
|
||||
of this code was written as part of a project to build a fixed-point vector
|
||||
processor in collaboration with the University of California at Berkeley,
|
||||
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
|
||||
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
|
||||
arithmetic/SoftFloat.html'.
|
||||
|
||||
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
|
||||
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
|
||||
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
|
||||
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
|
||||
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
|
||||
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
|
||||
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
|
||||
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
|
||||
|
||||
Derivative works are acceptable, even for commercial purposes, so long as
|
||||
(1) the source code for the derivative work includes prominent notice that
|
||||
the work is derivative, and (2) the source code includes prominent notice with
|
||||
these four paragraphs for those parts of this code that are retained.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| The macro `FLOATX80' must be defined to enable the extended double-precision
|
||||
| floating-point format `floatx80'. If this macro is not defined, the
|
||||
| `floatx80' type will not be defined, and none of the functions that either
|
||||
| input or output the `floatx80' type will be defined. The same applies to
|
||||
| the `FLOAT128' macro and the quadruple-precision format `float128'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define FLOATX80
|
||||
#define FLOAT128
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE floating-point types.
|
||||
*----------------------------------------------------------------------------*/
|
||||
typedef bits32 float32;
|
||||
typedef bits64 float64;
|
||||
#ifdef FLOATX80
|
||||
typedef struct {
|
||||
bits16 high;
|
||||
bits64 low;
|
||||
} floatx80;
|
||||
#endif
|
||||
#ifdef FLOAT128
|
||||
typedef struct {
|
||||
bits64 high, low;
|
||||
} float128;
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Primitive arithmetic functions, including multi-word arithmetic, and
|
||||
| division and square root approximations. (Can be specialized to target if
|
||||
| desired.)
|
||||
*----------------------------------------------------------------------------*/
|
||||
#include "softfloat-macros"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE floating-point underflow tininess-detection mode.
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern int8 float_detect_tininess;
|
||||
enum {
|
||||
float_tininess_after_rounding = 0,
|
||||
float_tininess_before_rounding = 1
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE floating-point rounding mode.
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern int8 float_rounding_mode;
|
||||
enum {
|
||||
float_round_nearest_even = 0,
|
||||
float_round_to_zero = 1,
|
||||
float_round_down = 2,
|
||||
float_round_up = 3
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE floating-point exception flags.
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern int8 float_exception_flags;
|
||||
enum {
|
||||
float_flag_invalid = 0x01, float_flag_denormal = 0x02, float_flag_divbyzero = 0x04, float_flag_overflow = 0x08,
|
||||
float_flag_underflow = 0x10, float_flag_inexact = 0x20
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Routine to raise any or all of the software IEC/IEEE floating-point
|
||||
| exception flags.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void float_raise( int8 );
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE integer-to-floating-point conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float32 int32_to_float32( int32 );
|
||||
float64 int32_to_float64( int32 );
|
||||
#ifdef FLOATX80
|
||||
floatx80 int32_to_floatx80( int32 );
|
||||
#endif
|
||||
#ifdef FLOAT128
|
||||
float128 int32_to_float128( int32 );
|
||||
#endif
|
||||
float32 int64_to_float32( int64 );
|
||||
float64 int64_to_float64( int64 );
|
||||
#ifdef FLOATX80
|
||||
floatx80 int64_to_floatx80( int64 );
|
||||
#endif
|
||||
#ifdef FLOAT128
|
||||
float128 int64_to_float128( int64 );
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE single-precision conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
int32 float32_to_int32( float32 );
|
||||
int32 float32_to_int32_round_to_zero( float32 );
|
||||
int64 float32_to_int64( float32 );
|
||||
int64 float32_to_int64_round_to_zero( float32 );
|
||||
float64 float32_to_float64( float32 );
|
||||
#ifdef FLOATX80
|
||||
floatx80 float32_to_floatx80( float32 );
|
||||
#endif
|
||||
#ifdef FLOAT128
|
||||
float128 float32_to_float128( float32 );
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE single-precision operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float32 float32_round_to_int( float32 );
|
||||
float32 float32_add( float32, float32 );
|
||||
float32 float32_sub( float32, float32 );
|
||||
float32 float32_mul( float32, float32 );
|
||||
float32 float32_div( float32, float32 );
|
||||
float32 float32_rem( float32, float32 );
|
||||
float32 float32_sqrt( float32 );
|
||||
flag float32_eq( float32, float32 );
|
||||
flag float32_le( float32, float32 );
|
||||
flag float32_lt( float32, float32 );
|
||||
flag float32_eq_signaling( float32, float32 );
|
||||
flag float32_le_quiet( float32, float32 );
|
||||
flag float32_lt_quiet( float32, float32 );
|
||||
flag float32_is_signaling_nan( float32 );
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE double-precision conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
int32 float64_to_int32( float64 );
|
||||
int32 float64_to_int32_round_to_zero( float64 );
|
||||
int64 float64_to_int64( float64 );
|
||||
int64 float64_to_int64_round_to_zero( float64 );
|
||||
float32 float64_to_float32( float64 );
|
||||
#ifdef FLOATX80
|
||||
floatx80 float64_to_floatx80( float64 );
|
||||
#endif
|
||||
#ifdef FLOAT128
|
||||
float128 float64_to_float128( float64 );
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE double-precision operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float64 float64_round_to_int( float64 );
|
||||
float64 float64_add( float64, float64 );
|
||||
float64 float64_sub( float64, float64 );
|
||||
float64 float64_mul( float64, float64 );
|
||||
float64 float64_div( float64, float64 );
|
||||
float64 float64_rem( float64, float64 );
|
||||
float64 float64_sqrt( float64 );
|
||||
flag float64_eq( float64, float64 );
|
||||
flag float64_le( float64, float64 );
|
||||
flag float64_lt( float64, float64 );
|
||||
flag float64_eq_signaling( float64, float64 );
|
||||
flag float64_le_quiet( float64, float64 );
|
||||
flag float64_lt_quiet( float64, float64 );
|
||||
flag float64_is_signaling_nan( float64 );
|
||||
|
||||
#ifdef FLOATX80
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE extended double-precision conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
int32 floatx80_to_int32( floatx80 );
|
||||
int32 floatx80_to_int32_round_to_zero( floatx80 );
|
||||
int64 floatx80_to_int64( floatx80 );
|
||||
int64 floatx80_to_int64_round_to_zero( floatx80 );
|
||||
float32 floatx80_to_float32( floatx80 );
|
||||
float64 floatx80_to_float64( floatx80 );
|
||||
#ifdef FLOAT128
|
||||
float128 floatx80_to_float128( floatx80 );
|
||||
#endif
|
||||
floatx80 floatx80_scale(floatx80 a, floatx80 b);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Packs the sign `zSign', exponent `zExp', and significand `zSig' into an
|
||||
| extended double-precision floating-point value, returning the result.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline floatx80 packFloatx80( flag zSign, int32 zExp, bits64 zSig )
|
||||
{
|
||||
floatx80 z;
|
||||
|
||||
z.low = zSig;
|
||||
z.high = ( ( (bits16) zSign )<<15 ) + zExp;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE extended double-precision rounding precision. Valid
|
||||
| values are 32, 64, and 80.
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern int8 floatx80_rounding_precision;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE extended double-precision operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
floatx80 floatx80_round_to_int( floatx80 );
|
||||
floatx80 floatx80_add( floatx80, floatx80 );
|
||||
floatx80 floatx80_sub( floatx80, floatx80 );
|
||||
floatx80 floatx80_mul( floatx80, floatx80 );
|
||||
floatx80 floatx80_div( floatx80, floatx80 );
|
||||
floatx80 floatx80_rem( floatx80, floatx80 );
|
||||
floatx80 floatx80_sqrt( floatx80 );
|
||||
flag floatx80_eq( floatx80, floatx80 );
|
||||
flag floatx80_le( floatx80, floatx80 );
|
||||
flag floatx80_lt( floatx80, floatx80 );
|
||||
flag floatx80_eq_signaling( floatx80, floatx80 );
|
||||
flag floatx80_le_quiet( floatx80, floatx80 );
|
||||
flag floatx80_lt_quiet( floatx80, floatx80 );
|
||||
flag floatx80_is_signaling_nan( floatx80 );
|
||||
|
||||
/* int floatx80_fsin(floatx80 &a);
|
||||
int floatx80_fcos(floatx80 &a);
|
||||
int floatx80_ftan(floatx80 &a); */
|
||||
|
||||
floatx80 floatx80_flognp1(floatx80 a);
|
||||
floatx80 floatx80_flogn(floatx80 a);
|
||||
floatx80 floatx80_flog2(floatx80 a);
|
||||
floatx80 floatx80_flog10(floatx80 a);
|
||||
|
||||
// roundAndPackFloatx80 used to be in softfloat-round-pack, is now in softfloat.c
|
||||
floatx80 roundAndPackFloatx80(int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FLOAT128
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE quadruple-precision conversion routines.
|
||||
*----------------------------------------------------------------------------*/
|
||||
int32 float128_to_int32( float128 );
|
||||
int32 float128_to_int32_round_to_zero( float128 );
|
||||
int64 float128_to_int64( float128 );
|
||||
int64 float128_to_int64_round_to_zero( float128 );
|
||||
float32 float128_to_float32( float128 );
|
||||
float64 float128_to_float64( float128 );
|
||||
#ifdef FLOATX80
|
||||
floatx80 float128_to_floatx80( float128 );
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Software IEC/IEEE quadruple-precision operations.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float128 float128_round_to_int( float128 );
|
||||
float128 float128_add( float128, float128 );
|
||||
float128 float128_sub( float128, float128 );
|
||||
float128 float128_mul( float128, float128 );
|
||||
float128 float128_div( float128, float128 );
|
||||
float128 float128_rem( float128, float128 );
|
||||
float128 float128_sqrt( float128 );
|
||||
flag float128_eq( float128, float128 );
|
||||
flag float128_le( float128, float128 );
|
||||
flag float128_lt( float128, float128 );
|
||||
flag float128_eq_signaling( float128, float128 );
|
||||
flag float128_le_quiet( float128, float128 );
|
||||
flag float128_lt_quiet( float128, float128 );
|
||||
flag float128_is_signaling_nan( float128 );
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Packs the sign `zSign', the exponent `zExp', and the significand formed
|
||||
| by the concatenation of `zSig0' and `zSig1' into a quadruple-precision
|
||||
| floating-point value, returning the result. After being shifted into the
|
||||
| proper positions, the three fields `zSign', `zExp', and `zSig0' are simply
|
||||
| added together to form the most significant 32 bits of the result. This
|
||||
| means that any integer portion of `zSig0' will be added into the exponent.
|
||||
| Since a properly normalized significand will have an integer portion equal
|
||||
| to 1, the `zExp' input should be 1 less than the desired result exponent
|
||||
| whenever `zSig0' and `zSig1' concatenated form a complete, normalized
|
||||
| significand.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline float128
|
||||
packFloat128( flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
|
||||
{
|
||||
float128 z;
|
||||
|
||||
z.low = zSig1;
|
||||
z.high = ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<48 ) + zSig0;
|
||||
return z;
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
|
||||
| and extended significand formed by the concatenation of `zSig0', `zSig1',
|
||||
| and `zSig2', and returns the proper quadruple-precision floating-point value
|
||||
| corresponding to the abstract input. Ordinarily, the abstract value is
|
||||
| simply rounded and packed into the quadruple-precision format, with the
|
||||
| inexact exception raised if the abstract input cannot be represented
|
||||
| exactly. However, if the abstract value is too large, the overflow and
|
||||
| inexact exceptions are raised and an infinity or maximal finite value is
|
||||
| returned. If the abstract value is too small, the input value is rounded to
|
||||
| a subnormal number, and the underflow and inexact exceptions are raised if
|
||||
| the abstract input cannot be represented exactly as a subnormal quadruple-
|
||||
| precision floating-point number.
|
||||
| The input significand must be normalized or smaller. If the input
|
||||
| significand is not normalized, `zExp' must be 0; in that case, the result
|
||||
| returned is a subnormal number, and it must not require rounding. In the
|
||||
| usual case that the input significand is normalized, `zExp' must be 1 less
|
||||
| than the ``true'' floating-point exponent. The handling of underflow and
|
||||
| overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline float128
|
||||
roundAndPackFloat128(
|
||||
flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1, bits64 zSig2 )
|
||||
{
|
||||
int8 roundingMode;
|
||||
flag roundNearestEven, increment, isTiny;
|
||||
|
||||
roundingMode = float_rounding_mode;
|
||||
roundNearestEven = ( roundingMode == float_round_nearest_even );
|
||||
increment = ( (sbits64) zSig2 < 0 );
|
||||
if ( ! roundNearestEven ) {
|
||||
if ( roundingMode == float_round_to_zero ) {
|
||||
increment = 0;
|
||||
}
|
||||
else {
|
||||
if ( zSign ) {
|
||||
increment = ( roundingMode == float_round_down ) && zSig2;
|
||||
}
|
||||
else {
|
||||
increment = ( roundingMode == float_round_up ) && zSig2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( 0x7FFD <= (bits32) zExp ) {
|
||||
if ( ( 0x7FFD < zExp )
|
||||
|| ( ( zExp == 0x7FFD )
|
||||
&& eq128(
|
||||
LIT64( 0x0001FFFFFFFFFFFF ),
|
||||
LIT64( 0xFFFFFFFFFFFFFFFF ),
|
||||
zSig0,
|
||||
zSig1
|
||||
)
|
||||
&& increment
|
||||
)
|
||||
) {
|
||||
float_raise( float_flag_overflow | float_flag_inexact );
|
||||
if ( ( roundingMode == float_round_to_zero )
|
||||
|| ( zSign && ( roundingMode == float_round_up ) )
|
||||
|| ( ! zSign && ( roundingMode == float_round_down ) )
|
||||
) {
|
||||
return
|
||||
packFloat128(
|
||||
zSign,
|
||||
0x7FFE,
|
||||
LIT64( 0x0000FFFFFFFFFFFF ),
|
||||
LIT64( 0xFFFFFFFFFFFFFFFF )
|
||||
);
|
||||
}
|
||||
return packFloat128( zSign, 0x7FFF, 0, 0 );
|
||||
}
|
||||
if ( zExp < 0 ) {
|
||||
isTiny =
|
||||
( float_detect_tininess == float_tininess_before_rounding )
|
||||
|| ( zExp < -1 )
|
||||
|| ! increment
|
||||
|| lt128(
|
||||
zSig0,
|
||||
zSig1,
|
||||
LIT64( 0x0001FFFFFFFFFFFF ),
|
||||
LIT64( 0xFFFFFFFFFFFFFFFF )
|
||||
);
|
||||
shift128ExtraRightJamming(
|
||||
zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 );
|
||||
zExp = 0;
|
||||
if ( isTiny && zSig2 ) float_raise( float_flag_underflow );
|
||||
if ( roundNearestEven ) {
|
||||
increment = ( (sbits64) zSig2 < 0 );
|
||||
}
|
||||
else {
|
||||
if ( zSign ) {
|
||||
increment = ( roundingMode == float_round_down ) && zSig2;
|
||||
}
|
||||
else {
|
||||
increment = ( roundingMode == float_round_up ) && zSig2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( zSig2 ) float_exception_flags |= float_flag_inexact;
|
||||
if ( increment ) {
|
||||
add128( zSig0, zSig1, 0, 1, &zSig0, &zSig1 );
|
||||
zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven );
|
||||
}
|
||||
else {
|
||||
if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0;
|
||||
}
|
||||
return packFloat128( zSign, zExp, zSig0, zSig1 );
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
|
||||
| and significand formed by the concatenation of `zSig0' and `zSig1', and
|
||||
| returns the proper quadruple-precision floating-point value corresponding
|
||||
| to the abstract input. This routine is just like `roundAndPackFloat128'
|
||||
| except that the input significand has fewer bits and does not have to be
|
||||
| normalized. In all cases, `zExp' must be 1 less than the ``true'' floating-
|
||||
| point exponent.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
static inline float128
|
||||
normalizeRoundAndPackFloat128(
|
||||
flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
|
||||
{
|
||||
int8 shiftCount;
|
||||
bits64 zSig2;
|
||||
|
||||
if ( zSig0 == 0 ) {
|
||||
zSig0 = zSig1;
|
||||
zSig1 = 0;
|
||||
zExp -= 64;
|
||||
}
|
||||
shiftCount = countLeadingZeros64( zSig0 ) - 15;
|
||||
if ( 0 <= shiftCount ) {
|
||||
zSig2 = 0;
|
||||
shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
|
||||
}
|
||||
else {
|
||||
shift128ExtraRightJamming(
|
||||
zSig0, zSig1, 0, - shiftCount, &zSig0, &zSig1, &zSig2 );
|
||||
}
|
||||
zExp -= shiftCount;
|
||||
return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user