Initial. Don't... just don't ask.
This commit is contained in:
commit
00bae13bba
586 changed files with 129057 additions and 0 deletions
23
obsolete/support/0-README
Normal file
23
obsolete/support/0-README
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
This contains the source for a Borland C++ program that allows you to dump
|
||||
the register contents for any BIOS video mode. 'vga.exe' should work with
|
||||
any VGA/SVGA adapter. It takes a hexadecimal mode number as argument and
|
||||
writes the (VGA) register contents to the console.
|
||||
|
||||
These printout can be used to write a new driver. Please read also 'man 7
|
||||
svgalib.et4000' about the tseng3.exe program.
|
||||
|
||||
trap-out.asm / .com is a DOS program which traces all I/O calls made when a
|
||||
given video mode is set by the BIOS. It was used for the TVGA driver and should
|
||||
be useful for other drivers too, esp. if no documentation is available.
|
||||
|
||||
It spits out a long list of "T DX/I AX/L" strings where T is "I" for IN or
|
||||
"O" for OUT, DX/I is the value of DX or the immediate given value for
|
||||
ports <256, and AX/L is the value of AX or AL before the call to IN or OUT
|
||||
(yeah, the value of AX is pretty worthless before a call to IN, but oh
|
||||
well)
|
||||
|
||||
This output is very very easily parsed into a simple C routine that calls
|
||||
port_in and port_out many many times, but will set the same mode the BIOS
|
||||
did.
|
||||
|
||||
The trap-out program is courtesy of Ryan Rubley <rubleyr@river.it.gvsu.edu>
|
||||
344
obsolete/support/trap-out.asm
Normal file
344
obsolete/support/trap-out.asm
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
; TRAPOUT2.ASM v2.0 by ARK (ark@lhq.com, root@ark.dyn.ml.org) 11-28-97
|
||||
; Traps IN and OUT instructions in INT 10h and displays DX and AX/AL values.
|
||||
;
|
||||
; In the header "T DX/I AX/L", T is the Type of instruction (I=IN, O=OUT),
|
||||
; DX/I is the value of DX or the Immediate value if port<256, and AX/L
|
||||
; is the value of AX or AL depending on if an 8 or 16 bit value is listed.
|
||||
; AX/L is meaningless for IN's since it is the value if AX/L *before* the
|
||||
; call to IN.
|
||||
;
|
||||
; This is very useful to find information about how your video card works.
|
||||
; I wrote this to get register dumps for my Trident TVGA9440AGi card so
|
||||
; that I could use it under Linux.
|
||||
;
|
||||
; NOTE: Pipe the output or you won't see anything!
|
||||
; (ex: TRAP-OUT 4F02 0101 > 640x480.256)
|
||||
;
|
||||
; New in v2.0:
|
||||
; * Traces into INT 10 calls that are called from inside INT 10!
|
||||
; * Allows AX and BX values to be specified!
|
||||
; * Command line accepts trailing spaces now.
|
||||
; x Code to trap INT's also! (T column='N', DX/I=INT ##, AX/L=AX value)
|
||||
; (Its commented out - but you can recompile with it if you want)
|
||||
;
|
||||
; How to assemble with Borland:
|
||||
; tasm /ml /zd ncr.asm (case sensitive, line number debug info only)
|
||||
; tlink /x /t ncr.obj (no map, make com file)
|
||||
;
|
||||
|
||||
.model tiny ; Tiny memory model, all segments point to the same 64K
|
||||
.286 ; This code will run on a 286... actually, it
|
||||
.code ; Everything is in the code segment(cs) will probably
|
||||
.startup ; Startup run on anything
|
||||
|
||||
jmp Start ; Go to beginning of progam
|
||||
realINT1 dd 52411A3Eh ; Address of original INT 01h routine offset
|
||||
realINT10 dd 3C1B214Bh ; Memory for [es:bx] of the real INT 10h
|
||||
; (defaults are '>-ARK!-<' just for looks in the .COM)
|
||||
|
||||
; strings
|
||||
no_command_line db 'Use: TRAPOUT2 [AX] [BX]',13,10
|
||||
db ' Traces all IN/OUT calls inside INT 10h',13,10,36
|
||||
tracing db 'Tracing INT 10h with AX:',36
|
||||
bx_msg db ' BX:',36
|
||||
header db 13,10,'T DX/I AX/L',13,10,36
|
||||
|
||||
INT1 proc ; Interrupt Service Routine for Single Step Debugging
|
||||
push ax ; save registers
|
||||
push dx
|
||||
push es
|
||||
push di
|
||||
push bp
|
||||
|
||||
mov bp,sp ; set bp to the stack
|
||||
push word ptr cs:[bp+12] ; put the real cs
|
||||
pop es ; into es
|
||||
push word ptr cs:[bp+10] ; put the real ip
|
||||
pop di ; into di
|
||||
mov al,byte ptr es:[di] ; set al to the next instruction that will
|
||||
; be executed after this INT 01 is done.
|
||||
|
||||
; This code will trap INT's also...
|
||||
; cmp al,0CDh ; If al is not CD (INT) keep going
|
||||
; jne not_int ; If it is, display some stuff...
|
||||
;; This will skip doing the INT's...
|
||||
;; add word ptr cs:[bp+10],2 ; Add 2 to the real ip, to skip the INT
|
||||
; mov dl,4Eh ; Display an N
|
||||
; mov ah,02h ; The immediate value/DX is the INT ##
|
||||
; int 21h ; that is called. AX is the value before
|
||||
; mov dl,20h ; Display a space
|
||||
; mov ah,02h ;
|
||||
; int 21h ; Display the immediate value which is
|
||||
; jmp is_imm ; reallly the interrupt number called.
|
||||
|
||||
not_int:
|
||||
and al,0F4h ; If al is E4-E7 or EC-EF (all IN/OUT's)
|
||||
cmp al,0E4h ; Then we display our stuff
|
||||
jne not_io ; Otherwise, do nothing
|
||||
; note: 1 more byte of code after this
|
||||
; jmp will make it out of range...
|
||||
|
||||
mov al,byte ptr es:[di] ; Set al to next instruction
|
||||
test al,02h ; If bit 1 is set then we have an OUT
|
||||
jz is_in ; If bit 1 is 0, we have an IN
|
||||
|
||||
mov dl,4Fh ; Display an O
|
||||
mov ah,02h
|
||||
int 21h
|
||||
jmp dx_or_imd
|
||||
|
||||
is_in: ; Display an I
|
||||
mov dl,49h
|
||||
mov ah,02h
|
||||
int 21h
|
||||
|
||||
dx_or_imd: ; Display a space
|
||||
mov dl,20h
|
||||
mov ah,02h
|
||||
int 21h
|
||||
|
||||
mov al,byte ptr es:[di] ; Set al to next instruction
|
||||
test al,08h ; If bit 3 is set then we are using DX
|
||||
jz is_imm ; If bit 3 is 0, we are using an immediate
|
||||
|
||||
mov ax,[bp+6] ; restore dx to ax
|
||||
call ShowHex ; Display dx
|
||||
call ShowHex
|
||||
call ShowHex
|
||||
call ShowHex
|
||||
jmp ax_or_al
|
||||
|
||||
is_imm:
|
||||
mov dl,20h ; Display 2 spaces
|
||||
mov ah,02h
|
||||
int 21h
|
||||
mov dl,20h
|
||||
mov ah,02h
|
||||
int 21h
|
||||
|
||||
mov ah,byte ptr es:[di+1] ; Set ah to byte after the next instruction
|
||||
call ShowHex ; Display the immediate value
|
||||
call ShowHex
|
||||
|
||||
ax_or_al:
|
||||
mov dl,2Ch ; Display a comma
|
||||
mov ah,02h
|
||||
int 21h
|
||||
|
||||
mov al,byte ptr es:[di] ; Set al to next instruction
|
||||
test al,01h ; If bit 0 is set then we are using AX
|
||||
jz is_al ; If bit 0 is 0, we are using AL
|
||||
|
||||
mov ax,[bp+8] ; Restore ax
|
||||
call ShowHex ; Display ax
|
||||
call ShowHex
|
||||
call ShowHex
|
||||
call ShowHex
|
||||
jmp print_next_line
|
||||
|
||||
is_al:
|
||||
mov ah,[bp+8] ; Restore al to ah
|
||||
call ShowHex ; Display al
|
||||
call ShowHex
|
||||
|
||||
print_next_line:
|
||||
mov dl,0Dh ; print a newline
|
||||
mov ah,02h
|
||||
int 21h
|
||||
mov dl,0Ah
|
||||
mov ah,02h
|
||||
int 21h
|
||||
|
||||
not_io:
|
||||
pop bp ; restore registers
|
||||
pop di
|
||||
pop es
|
||||
pop dx
|
||||
pop ax
|
||||
iret ; end interrupt
|
||||
INT1 endp
|
||||
|
||||
; INT 10h that fakes the real INT 10 and sets the trap flag.
|
||||
INT10 proc ; Interrupt Service Routine for Tracing INT 10h
|
||||
push ax ; Save AX
|
||||
pushf ; Put flags on the stack
|
||||
pop ax ; Then into AX
|
||||
or ax,0100h ; Set the trap flag
|
||||
push ax ; Trap Flag calls INT 01h between every instruction
|
||||
popf ; Stuff new flags back into the flags register
|
||||
pop ax ; Restore AX
|
||||
|
||||
cli ; Fake INT call: clear interrupt flag, skip clearing
|
||||
pushf ; trap flag, push flags, call to location.
|
||||
call cs:[realINT10] ; This call to INT 10h is be trapped for
|
||||
; IN/OUT/INT Normal INT calls would clear
|
||||
; the trap flag and then INT 01h would never
|
||||
; be called.
|
||||
iret ; end interrupt
|
||||
INT10 endp
|
||||
|
||||
; function that prints the highest 4 bits of ax as text {0-9,A-F} to stdout
|
||||
; ax will be shifted left 4 bits on return.
|
||||
ShowHex proc
|
||||
push ax ; save registers
|
||||
push dx
|
||||
|
||||
shr ax,0Ch ; move the highest 4 bits to the lowest 4
|
||||
and al,0Fh ; limit to lowest 4 bits
|
||||
or al,30h ; change range to 30h-3Fh {0-9:;<=>?}
|
||||
cmp al,39h ; if it is 30h-39h
|
||||
jbe is_0_thru_9 ; then its already set
|
||||
add al,07h ; otherwise change :;<=>? to A-F
|
||||
is_0_thru_9:
|
||||
mov dl,al
|
||||
mov ah,02h
|
||||
int 21h
|
||||
|
||||
pop dx ; restore dx
|
||||
pop ax ; restore ax
|
||||
shl ax,4 ; set up ax for next call
|
||||
ret ; return
|
||||
ShowHex endp
|
||||
|
||||
Start: ; Program begins here
|
||||
mov si,0080h ; CS:0080h is the command line
|
||||
cmp byte ptr [si],10 ; I want it to be at least 10 bytes long
|
||||
jae process_command_line ; if not, abort
|
||||
|
||||
mov dx,offset no_command_line ; ds is preset
|
||||
mov ah,09h ; Dos function 09h
|
||||
int 21h ; Display no command line string
|
||||
ret ; Exit program
|
||||
|
||||
process_command_line:
|
||||
inc si ; move si to start of actual string
|
||||
mov ax,[si+1] ; copy first 2 chrs to ax, skipping the space
|
||||
mov bx,[si+3] ; copy 2nd two characters to bx
|
||||
sub al,30h ; subtract 30h so chrs 0-9 have value 0-9
|
||||
cmp al,09h ; if its 0-9, its ok.
|
||||
jbe al_is_ok ; if its not, its probably A-F or a-f
|
||||
sub al,07h ; so subtract 7 more
|
||||
and al,0Fh ; and limit to 0-F
|
||||
al_is_ok:
|
||||
sub ah,30h ; do the same to ah
|
||||
cmp ah,09h
|
||||
jbe ah_is_ok
|
||||
sub ah,07h
|
||||
and ah,0Fh
|
||||
ah_is_ok:
|
||||
sub bl,30h ; do the same to bl
|
||||
cmp bl,09h
|
||||
jbe bl_is_ok
|
||||
sub bl,07h
|
||||
and bl,0Fh
|
||||
bl_is_ok:
|
||||
sub bh,30h ; do the same to bh
|
||||
cmp bh,09h
|
||||
jbe bh_is_ok
|
||||
sub bh,07h
|
||||
and bh,0Fh
|
||||
bh_is_ok:
|
||||
shl al,04h ; Combine the values so that AL-AH-BL-BH
|
||||
or ah,al ; Goes into --AH- --AL-
|
||||
mov al,bl ; <----AX--->
|
||||
shl al,04h
|
||||
or al,bh
|
||||
mov word ptr [si],ax ; store the value over the string
|
||||
|
||||
mov ax,[si+6] ; copy 3rd 2 chrs to ax, skip the 2nd space
|
||||
mov bx,[si+8] ; copy 4th two characters to bx
|
||||
sub al,30h ; subtract 30h so chrs 0-9 have value 0-9
|
||||
cmp al,09h ; if its 0-9, its ok.
|
||||
jbe al_is_ok2 ; if its not, its probably A-F or a-f
|
||||
sub al,07h ; so subtract 7 more
|
||||
and al,0Fh ; and limit to 0-F
|
||||
al_is_ok2:
|
||||
sub ah,30h ; do the same to ah
|
||||
cmp ah,09h
|
||||
jbe ah_is_ok2
|
||||
sub ah,07h
|
||||
and ah,0Fh
|
||||
ah_is_ok2:
|
||||
sub bl,30h ; do the same to bl
|
||||
cmp bl,09h
|
||||
jbe bl_is_ok2
|
||||
sub bl,07h
|
||||
and bl,0Fh
|
||||
bl_is_ok2:
|
||||
sub bh,30h ; do the same to bh
|
||||
cmp bh,09h
|
||||
jbe bh_is_ok2
|
||||
sub bh,07h
|
||||
and bh,0Fh
|
||||
bh_is_ok2:
|
||||
shl al,04h ; Combine the values so that AL-AH-BL-BH
|
||||
or ah,al ; Goes into --AH- --AL-
|
||||
mov al,bl ; <----AX--->
|
||||
shl al,04h
|
||||
or al,bh
|
||||
mov word ptr [si+2],ax ; store the value over the string
|
||||
; Now [si] contains the real values of AX and BX
|
||||
|
||||
mov dx,offset tracing ; ds is preset
|
||||
mov ah,09h ; Dos function 09h
|
||||
int 21h ; Display tracing string
|
||||
mov ax,word ptr [si] ; Restore ax
|
||||
call ShowHex ; Display command line
|
||||
call ShowHex ; ax value back to user
|
||||
call ShowHex ; by placing it in ax
|
||||
call ShowHex ; and calling ShowHex
|
||||
mov dx,offset bx_msg ; ds is preset
|
||||
mov ah,09h ; Dos function 09h
|
||||
int 21h ; Display bx message
|
||||
mov ax,word ptr [si+2] ; Restore bx into ax
|
||||
call ShowHex ; Display command line
|
||||
call ShowHex ; bx value back to user
|
||||
call ShowHex ; by placing it in ax
|
||||
call ShowHex ; and calling ShowHex
|
||||
mov dx,offset header ; ds is preset
|
||||
mov ah,09h ; Dos function 09h
|
||||
int 21h ; Display header to output
|
||||
|
||||
mov ax,3501h ; Dos function 35h, Get vector of INT 01h
|
||||
int 21h ; Store it in es:bx
|
||||
mov word ptr [realINT1],bx ; Store address of original INT 01h
|
||||
mov word ptr [realINT1+2],es ; into realINT1
|
||||
|
||||
mov ax,3510h ; Dos function 35h, Get vector of INT 10h
|
||||
int 21h ; Store it in es:bx
|
||||
mov word ptr [realINT10],bx ; Store address of original INT 10h
|
||||
mov word ptr [realINT10+2],es ; into realINT10 so we can fake an INT
|
||||
|
||||
mov ax,2501h ; Dos function 25h, Store DS:DX to INT 01h
|
||||
mov dx,offset INT1 ; ds is preset, dx is the handler's offset
|
||||
int 21h ; Set new Single Step handler
|
||||
|
||||
mov ax,2510h ; Dos function 25h, Store DS:DX to INT 10h
|
||||
mov dx,offset INT10 ; ds is preset, dx is the handler's offset
|
||||
int 21h ; Set new Video Interrupt
|
||||
|
||||
mov ax,word ptr [si] ; We will use the command line ax/bx
|
||||
mov bx,word ptr [si+2] ; values for the fake int call
|
||||
int 10h ; Call my int 10 which fakes the
|
||||
; real int 10 and traps it.
|
||||
|
||||
mov ax,2501h ; Dos function 25h, Store DS:DX to INT 01h
|
||||
mov dx,word ptr [realINT1] ; ds/dx are in realINT1
|
||||
push ds ; Save old ds
|
||||
push word ptr [realINT1+2] ; Put segment on stack
|
||||
pop ds ; Set ds to the segment
|
||||
int 21h ; Reset old Single Step handler
|
||||
pop ds ; Restore old ds
|
||||
|
||||
mov ax,2510h ; Dos function 25h, Store DS:DX to INT 10h
|
||||
mov dx,word ptr [realINT10] ; ds/dx are in realINT10
|
||||
push ds ; Save old ds
|
||||
push word ptr [realINT10+2] ; Put segment on stack
|
||||
pop ds ; Set ds to the segment
|
||||
int 21h ; Reset old Video Interrupt
|
||||
pop ds ; Restore old ds
|
||||
|
||||
mov ax,0003h ; Set ax to 3
|
||||
int 10h ; Set 80x25 Text mode
|
||||
ret ; End of program
|
||||
end ; End of file
|
||||
BIN
obsolete/support/trap-out.com
Normal file
BIN
obsolete/support/trap-out.com
Normal file
Binary file not shown.
146
obsolete/support/vga.c
Normal file
146
obsolete/support/vga.c
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dos.h>
|
||||
|
||||
/* January 1995, Scott Heavner (sdh@po.cwru.edu)
|
||||
|
||||
* Changes to allow anyone to compile vga.c under the go32 Linux->dos cross compiler.
|
||||
* It should also work with DJGPP (the gcc port to msdos). The cross compiler is
|
||||
* available at ftp://sunsite.unc.edu/pub/Linux/devel/msdos/go32crs.tar.gz.
|
||||
*
|
||||
* I compiled it with:
|
||||
*
|
||||
* go32gcc vga.c -lpc
|
||||
* cat /usr/local/go32/bin/go32.exe a.out > vga.exe
|
||||
*/
|
||||
#ifdef GO32
|
||||
#include <pc.h>
|
||||
#endif
|
||||
|
||||
/* VGA index register ports */
|
||||
#define CRT_I 0x3D4 /* CRT Controller Index (mono: 0x3B4) */
|
||||
#define ATT_IW 0x3C0 /* Attribute Controller Index & Data Write Register */
|
||||
#define GRA_I 0x3CE /* Graphics Controller Index */
|
||||
#define SEQ_I 0x3C4 /* Sequencer Index */
|
||||
#define PEL_IW 0x3C8 /* PEL Write Index */
|
||||
|
||||
/* VGA data register ports */
|
||||
#define CRT_D 0x3D5 /* CRT Controller Data Register (mono: 0x3B5) */
|
||||
#define ATT_R 0x3C1 /* Attribute Controller Data Read Register */
|
||||
#define GRA_D 0x3CF /* Graphics Controller Data Register */
|
||||
#define SEQ_D 0x3C5 /* Sequencer Data Register */
|
||||
#define MIS_R 0x3CC /* Misc Output Read Register */
|
||||
#define MIS_W 0x3C2 /* Misc Output Write Register */
|
||||
#define IS1_R 0x3DA /* Input Status Register 1 (mono: 0x3BA) */
|
||||
#define PEL_D 0x3C9 /* PEL Data Register */
|
||||
|
||||
/* VGA indexes max counts */
|
||||
#define CRT_C 24 /* 24 CRT Controller Registers */
|
||||
#define ATT_C 21 /* 21 Attribute Controller Registers */
|
||||
#define GRA_C 9 /* 9 Graphics Controller Registers */
|
||||
#define SEQ_C 5 /* 5 Sequencer Registers */
|
||||
#define MIS_C 1 /* 1 Misc Output Register */
|
||||
|
||||
/* VGA registers saving indexes */
|
||||
#define CRT 0 /* CRT Controller Registers start */
|
||||
#define ATT CRT+CRT_C /* Attribute Controller Registers start */
|
||||
#define GRA ATT+ATT_C /* Graphics Controller Registers start */
|
||||
#define SEQ GRA+GRA_C /* Sequencer Registers */
|
||||
#define MIS SEQ+SEQ_C /* General Registers */
|
||||
#define END MIS+MIS_C /* last */
|
||||
|
||||
|
||||
unsigned char vga_regs[60];
|
||||
|
||||
#ifdef GO32
|
||||
|
||||
#define port_out(v,p) outportb(p,v)
|
||||
#define port_in(p) inportb(p)
|
||||
|
||||
#else
|
||||
|
||||
void port_out(unsigned char value, unsigned short port)
|
||||
{
|
||||
asm
|
||||
{
|
||||
mov dx, port
|
||||
mov al, value
|
||||
out dx, al
|
||||
}
|
||||
} unsigned char port_in(unsigned short port)
|
||||
{
|
||||
asm
|
||||
{
|
||||
mov dx, port
|
||||
in al, dx
|
||||
} return (_AL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
union REGS cpu_regs;
|
||||
int i;
|
||||
unsigned char mode;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("Usage: getregs mode (mode must be hexadecimal)\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (!sscanf(argv[1], "%x", &mode)) {
|
||||
printf("Usage: getregs mode (mode must be hexadecimal)\n");
|
||||
exit(-1);
|
||||
}
|
||||
cpu_regs.h.ah = 0x00;
|
||||
cpu_regs.h.al = mode;
|
||||
int86(0x10, &cpu_regs, &cpu_regs);
|
||||
|
||||
/* get VGA register values */
|
||||
for (i = 0; i < CRT_C; i++) {
|
||||
port_out(i, CRT_I);
|
||||
vga_regs[CRT + i] = port_in(CRT_D);
|
||||
}
|
||||
for (i = 0; i < ATT_C; i++) {
|
||||
port_in(IS1_R);
|
||||
port_out(i, ATT_IW);
|
||||
vga_regs[ATT + i] = port_in(ATT_R);
|
||||
}
|
||||
for (i = 0; i < GRA_C; i++) {
|
||||
port_out(i, GRA_I);
|
||||
vga_regs[GRA + i] = port_in(GRA_D);
|
||||
}
|
||||
for (i = 0; i < SEQ_C; i++) {
|
||||
port_out(i, SEQ_I);
|
||||
vga_regs[SEQ + i] = port_in(SEQ_D);
|
||||
}
|
||||
vga_regs[MIS] = port_in(MIS_R);
|
||||
|
||||
cpu_regs.h.ah = 0x00;
|
||||
cpu_regs.h.al = 0x03;
|
||||
int86(0x10, &cpu_regs, &cpu_regs);
|
||||
|
||||
printf("/* BIOS mode 0x%02X */\n", mode);
|
||||
printf("static char regs[60] = {\n ");
|
||||
for (i = 0; i < 12; i++)
|
||||
printf("0x%02X,", vga_regs[CRT + i]);
|
||||
printf("\n ");
|
||||
for (i = 12; i < CRT_C; i++)
|
||||
printf("0x%02X,", vga_regs[CRT + i]);
|
||||
printf("\n ");
|
||||
for (i = 0; i < 12; i++)
|
||||
printf("0x%02X,", vga_regs[ATT + i]);
|
||||
printf("\n ");
|
||||
for (i = 12; i < ATT_C; i++)
|
||||
printf("0x%02X,", vga_regs[ATT + i]);
|
||||
printf("\n ");
|
||||
for (i = 0; i < GRA_C; i++)
|
||||
printf("0x%02X,", vga_regs[GRA + i]);
|
||||
printf("\n ");
|
||||
for (i = 0; i < SEQ_C; i++)
|
||||
printf("0x%02X,", vga_regs[SEQ + i]);
|
||||
printf("\n ");
|
||||
printf("0x%02X", vga_regs[MIS]);
|
||||
printf("\n};\n");
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue