far jmp after enabling A20 triple faults

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
TwixEmma
Posts: 11
Joined: Tue Jul 16, 2013 10:10 am
Location: England
Contact:

far jmp after enabling A20 triple faults

Post by TwixEmma »

Hi, I've encountered a problem with my second stage bootloader code, after moving my 32bit code in memory to segment:0x0 offset:0x0 and enabling A20, I do a jmp to the 32bit code, but bochs triple faults and reboots. The error bochs gives me is this...
00050730801i[BIOS ] Booting from 0000:7c00
00050982740e[CPU0 ] fetch_raw_descriptor: GDT: index (1fe7) 3fc > limit (0)
00050982740e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00050982740e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00050982740i[CPU0 ] CPU is in protected mode (active)
00050982740i[CPU0 ] CS.mode = 16 bit
00050982740i[CPU0 ] SS.mode = 16 bit
00050982740i[CPU0 ] EFER = 0x00000000
00050982740i[CPU0 ] | EAX=60001fe0 EBX=0000000d ECX=0009fffd EDX=00000080
00050982740i[CPU0 ] | ESP=00007bda EBP=00007c00 ESI=000eff0b EDI=0000ff0b
00050982740i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf ZF af PF cf
00050982740i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00050982740i[CPU0 ] | CS:1fe0( 0004| 0| 0) 0001fe00 0000ffff 0 0
00050982740i[CPU0 ] | DS:0000( 0000| 0| 0) 00000000 00000000 0 0
00050982740i[CPU0 ] | SS:1fe0( 0005| 0| 0) 0001fe00 0000ffff 0 0
00050982740i[CPU0 ] | ES:0000( 0005| 0| 0) 00000000 0000ffff 0 0
00050982740i[CPU0 ] | FS:0000( 0005| 0| 0) 00000000 0000ffff 0 0
00050982740i[CPU0 ] | GS:0000( 0005| 0| 0) 00000000 0000ffff 0 0
00050982740i[CPU0 ] | EIP=00007c0c (00007c0c)
00050982740i[CPU0 ] | CR0=0x60000011 CR2=0x00000000
00050982740i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00050982740i[CPU0 ] 0x0000000000007c0c>> mov es, ax : 8EC0
00050982740e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00050982740i[SYS ] bx_pc_system_c::Reset(HARDWARE) called
00050982740i[CPU0 ] cpu hardware reset
for the GDT I copied a tutorial GDT, I figured it wouldn't make much of a difference to my own systems way of loading, but obviously I'm missing something. I've googled and searched this problem and a lot of people encounter this problem but I can't understand how to solve it. Here's my boot code so far:

Code: Select all

;stage 1 boot
use16
org 0x7C00
real_start:
cld
cli
sub ax, ax
mov ds, ax
mov bp, 0x7C00

mov ax, 0x1FE0
mov es, ax
mov si, bp
mov di, bp
mov cx, 0x0100
rep movsw              ;move boot code to the 0x1FE0:0x0000
jmp 0x1FE0:cont

loadseg_off dw 0
loadseg_seg dw 0x0060

cont:
mov ds,ax
mov ss,ax
lea sp,[bp-0x20]
sti

mov [drive],dl ;BIOS passes drive number in DL

main16:

call ClearScreen16

mov bx,00001101b;pink on black

mov [xpos],4d;xpos
mov [ypos],2d;ypos
call SetCursorPos16
mov si,bootstrapname
call PrintText16

mov [xpos],4d;xpos
mov [ypos],3d;ypos
call SetCursorPos16
mov si,loadingmsg
call PrintText16

mov [xpos],0
mov [ypos],5
call SetCursorPos16

call LoadStage2
cmp [errorflag],0

jg halt16
;jmp testinstead16
jmp loadpoint16 ;jump to loaded program

halt16:
mov bx,00001111b;white on black
mov [xpos],4d;xpos
mov [ypos],5d;ypos
call SetCursorPos16
mov si,haltexception
call PrintText16

mov [xpos],0
mov [ypos],7
call SetCursorPos16

testinstead16:
mov bx,00001111b;white on black
mov [xpos],4d;xpos
mov [ypos],5d;ypos
call SetCursorPos16
mov si,testexception
call PrintText16

mov [xpos],0
mov [ypos],7
call SetCursorPos16

hang16:
xor ah,ah
int 0x16             ; wait for a key
int 0x19             ; reboot the machine

ClearScreen16:
  pusha
  mov ah,00h
  mov al,03h
  int 10h
  popa
ret

SetCursorPos16:;dl = xpos, dh = ypos
  pusha
  mov ah,02h
  mov dl,[xpos]
  mov dh,[ypos]
  int 10h
  popa
ret

PrintText16:;si = string start position, bx = color to use
  pusha
  mov ah,09h
  mov bh,00h
  mov cx,01h
  .dochar:
    lodsb
    or al,al
    jz .return
    int 10h
    inc [xpos]
    call SetCursorPos16
    jmp .dochar
  .return:
  popa
ret

LoadStage2:
  pusha
  mov [counter1],1
  .tryread:
    mov ax,ds          ;segment
    mov es,ax
    mov bx,loadpoint16 ;offset
    mov ah,02h         ;read sectors into memory
    mov al,4d          ;load 4 sectors
    mov ch,00h         ;the track to read from
    mov cl,02h         ;sector id
    mov dh,00h         ;head
    mov dl,[drive]     ;drive
    int 13h
    jc .tryagain
    mov bx,00000101b;purple on black
    mov [xpos],4d;xpos
    mov [ypos],3d;ypos
    call SetCursorPos16
    mov si,donemsg
    jmp .fin
  .tryagain:
    inc [counter1]
    cmp [counter1],3
    jg .failed
    jmp .tryread
  .failed:
    mov bx,00000100b;red on black
    mov [xpos],4d;xpos
    mov [ypos],3d;ypos
    call SetCursorPos16
    mov si,errormsg
  .fin:
    call PrintText16
    mov [xpos],0d;xpos
    mov [ypos],5d;ypos
    call SetCursorPos16
  popa
ret

bootstrapname db "Wolf Bootloader         ",0
loadingmsg db    "Loading System...       ",0
errormsg db      "Failed to Load System   ",0
donemsg db       "System Loaded...        ",0
haltexception db "Loader Halted!          ",0
testexception db "Loader Tested!          ",0

drive db 0

xpos db 0
ypos db 0

errorflag db 0
counter1 db 0

ascii db 0x10 ;I use 0x10 value just to highlight this db in a hex viewer, since everything else around it is zeros
times 510-($-$$) db 0

dw 0xAA55
;end of stage 1 boot
;========================================= stage 1 works 100%
;stage 2 boot
loadpoint16:call ClearScreen16

;move the 32bit code in memory to absolute address 0x0000:0x0000, is this right?
;ds is already the correct segment value
mov si,Start32
xor ax,ax               ;0x0000
mov es,ax
mov di,ax

mov cx,End32-Start32    ;repeat for the length of 32bit code

rep movsb

;load GDT
cli

lgdt [gdt]

;enable A20
mov eax,cr0
or eax,1
mov cr0,eax
jmp 0x8 ;this triple faults

;additional routines
PrintNumber16:;ax = number
  pusha
    mov si,ascii
    call IntToString16
    call ReverseString16
    call PrintText16
  popa
ret

IntToString16:;si = buffer, ax = number
  pusha
  push si
  mov bx,10   ;divide by
  .asc2:
    xor dx,dx ;clear dx prior to dividing dx:ax by bx
    div bx    ;ax/10
    add dx,48 ;add 48 to remainder to get ascii character of number
    mov [si],dl
    inc si
    cmp ax,0
    jz .fin ;if ax==0, end of routine
    jmp .asc2
  .fin:
    mov byte [si],0
    pop si
  popa
ret

IntToHex16:;si = target buffer, number in ax
  pusha
  push si
  mov byte [si],'0'
  inc si
  mov byte [si],'x'
  inc si
  mov dx,ax
  mov cx,4               ; 4 hex digits
  .nextdigit:
    rol dx,4             ; rotate so that lowest 4 bits are used
    mov ax,0E0Fh         ; ah = request, al = mask for nybble
    and al,dl
    add al,90h           ; convert al to ascii hex (four instructions)
    daa                  ; I've spent 1 hour to understand how it works..
    adc al,40h
    daa
    mov byte [si],al
    inc si
    loop .nextdigit
  .fin:
    mov dx,ax
    mov byte [si],0
    pop si
  popa
ret

StrLen16:;si = start position of string
  pusha
  push si
  .count:
    cmp byte [si],0
    je .fin
    inc si
    jmp .count
  .fin:
    mov di,si
    pop si
    sub di,si
  popa
ret

ReverseString16:;si = string start position
  pusha
  push si
  mov di,si
  xor cx,cx
  .loop1:
    mov al,[si]
    xor ah,ah
    cmp al,0
    je .beginloop2
    push ax
    inc si
    inc cx
    jmp .loop1
  .beginloop2:
    mov si,di
  .loop2:
    pop ax
    mov [si],al
    inc si
    dec cx
    cmp cx,0
    jg .loop2
  .fin:
    pop si
  popa
ret

numdiv db ':',0

gdt:
        dq   0               ; dummy

        dw   0x07FF          ; 8Mb - limit=2047 (2048*4096=8Mb)
        dw   0x0000          ; base address=0
        dw   0x9A00          ; code read/exec
        dw   0x00C0          ; granularity=4096, 386

        dw   0x07FF          ; 8Mb - limit=2047 (2048*4096=8Mb)
        dw   0x0000          ; base address=0
        dw   0x9200          ; data read/write
        dw   0x00C0          ; granularity=4096, 386

idt_48:
        dw   0               ; idt limit=0
        dw   0,0             ; idt base=0L

gdt_48:
        dw   0x800           ; gdt limit=2048, 256 GDT entries
        dw   gdt,0x9         ; gdt base = 0X9xxxx

;end of stage 2 boot
;=========================================
;stage 3 boot
use32
org 0x0000
Start32:

shl esp,4

push dword 0
popf

call ClearScreen32
mov ebx,HelloWorld32
call PrintString32

hang32:
jmp hang32

Putch32:
 pusha
 mov edi,0xB8000         ;video memory
 xor eax,eax             ;clear eax
 mov ecx,80*2            ;mode 7 has 2 bytes per char, so its COLS*2 bytes per line
 mov al,byte [ypos]      ;get y pos
 mul ecx                 ;multiply y*COLS
 push eax                ;save eax, the multiplication
 mov al,byte [xpos]      ;multiple xpos by 2, because it is 2 bytes per char
 mov cl,2
 mul cl
 pop ecx                 ;pop y*COLS result
 add eax,ecx
 xor ecx,ecx
 add edi,eax             ;add it to the base address
 cmp bl,0x0A
 je .row
 mov dl,bl
 mov dh,14               ;char attribute
 mov word [edi],dx       ;write to video display
 inc byte [xpos]         ;go to next character
 cmp [xpos],80           ;are we at the end of the line?
 je .row
 jmp .fin
 .row:
  mov byte [xpos],0       ;go back to col 0
  inc byte [ypos]         ;go to next row
 .fin:
  popa
ret

PrintString32:
 pusha
 push ebx
 pop edi
 .loop:
  mov bl,byte [edi]
  cmp bl,0
  je .fin
  call Putch32
 .next:
  inc edi
  jmp .loop
 .fin:
  mov bh,byte [ypos]
  mov bl,byte [xpos]
  call SetCursorPos32
 popa
ret

SetCursorPos32:
 pusha
 xor eax,eax
 mov ecx,80
 mov al,bh
 mul ecx
 add al,bl
 mov ebx,eax
 mov al,0x0F
 mov dx,0x03D4
 out dx,al
 mov al,bl
 mov dx,0x03D5
 out dx,al
 xor eax,eax
 mov al,0x0E
 mov dx,0x03D4
 out dx,al
 mov al,bh
 mov dx,0x03D5
 out dx,al
 popa
ret

ClearScreen32:
 pusha
 cld
 mov edi,0xB8000         ;video memory
 mov cx,2000
 mov ah,14               ;char attribute
 mov al,' '
 rep stosw
 mov byte [xpos],0
 mov byte [ypos],0
 popa
ret

HelloWorld32 db "Hello 32Bit World!",0

End32:
;end of stage 3 boot
Any help, advice or fix is appreciated. Thanks in advance.
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: far jmp after enabling A20 triple faults

Post by iansjack »

You don't do a far jump to the 32-bit code; you do a near jump to 0x7c08.
User avatar
TwixEmma
Posts: 11
Joined: Tue Jul 16, 2013 10:10 am
Location: England
Contact:

Re: far jmp after enabling A20 triple faults

Post by TwixEmma »

iansjack wrote:You don't do a far jump to the 32-bit code; you do a near jump to 0x7c08.
Thanks for your reply but I believe you're missing the point, I tried your suggestion but it still triple faults. I move the 32bit code to 0x0000:0x0000
so 0x7C08 points to where?
"Don't think, don't try, just do." Master Yoda
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: far jmp after enabling A20 triple faults

Post by DavidCooper »

What is this?

Code: Select all

;enable A20
mov eax,cr0
or eax,1
mov cr0,eax
jmp 0x8 ;this triple faults
That code doesn't enable the A20, and the jump looks as if it will jump 8 bytes on from the byte immediately following that instruction to run whatever it happens to find there. Are you just mashing together bits of tutorial code without understanding what they do and how they work?

Your GDT values look horrible as well. Even if they happen to work to some degree, you need to read up on how to do it properly instead of copying someone else's junk.
Last edited by DavidCooper on Fri Jul 19, 2013 11:42 am, edited 1 time in total.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: far jmp after enabling A20 triple faults

Post by iansjack »

If you don't know what is at 0x7c08 in your binary you can be fairly confident that I don't either. You need to show us the new debug output (and also show us how you have altered your code) before we can guess at your current problem. You also need to set your DS and ES registers after the far jump before you read any memory locations.

Alternatively, just single-step through your code to see what is happening.
User avatar
TwixEmma
Posts: 11
Joined: Tue Jul 16, 2013 10:10 am
Location: England
Contact:

Re: far jmp after enabling A20 triple faults

Post by TwixEmma »

DavidCooper wrote:What is this?

Code: Select all

;enable A20
mov eax,cr0
or eax,1
mov cr0,eax
jmp 0x8 ;this triple faults
That code doesn't enable the A20, and the jump looks as if it will jump 8 bytes on from the byte immediately following that instruction to run whatever it happens to find there. Are you just mashing together bits of tutorial code without understanding what they do and how they work?

Your GDT values look horrible as well. Even if they happen to work to some degree, you need to read up on how to do it properly instead of copying someone else's junk.
I am not just mashing bits of tutorials, I just copied a GDT to test my code. the only things I've copied are the GDT and the hex printing routine (which works beautifully). everything else I've done the research and reading. the only thing I'm not sure about is how I move the 32bit code, is that right? or am I messing something. also am I doing the jmp right, I dont think I am but I don't know how I'd address the 32bit code otherwise. also the GDT is from the grub bootloader <3 I'll go over the GDT myself since its obviously faulty, then I'll update you. Thanks for your reply.

p.s. A20 is enabled by that code, it's probably not the best way of doing it though.
edit: forgot to mention the 32bit string printing code was copied, I was going to replace it once I got it loading 32bit pmode.
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: far jmp after enabling A20 triple faults

Post by iansjack »

The code is faulting at address 0x7c0c so obviously you are not jumping to 0x0. Just single-step the code, as I suggested before, and you will get a much better idea what is happening. (But first make the jump a far jump.)
User avatar
TwixEmma
Posts: 11
Joined: Tue Jul 16, 2013 10:10 am
Location: England
Contact:

Re: far jmp after enabling A20 triple faults

Post by TwixEmma »

iansjack wrote:The code is faulting at address 0x7c0c so obviously you are not jumping to 0x0. Just single-step the code, as I suggested before, and you will get a much better idea what is happening. (But first make the jump a far jump.)
I found the problem because I traced the exception from the bochs log, Ive stripped and refined my code of all printing routines to make the instruction stepping easier to read, and with the help of the osdev wiki I changed my gdt, a20 and segments code. The exception occurs at reloading the segments, the exception trace results as:
00025422617i[CPU0 ] 0x000000000000fcb4>> pusha : 60
00025422617e[CPU0 ] exception(): 3rd (12) exception with no resolution, shutdown status is 00h, resetting
Its complaining that im "destroying" the stack. But I don't know how to fix this :S
heres my code (stripped and refined):

Code: Select all

;stage 1 boot
use16
org 0x7C00
real_start:
cld
cli
sub ax, ax
mov ds, ax
mov bp, 0x7C00

mov ax, 0x1FE0
mov es, ax
mov si, bp
mov di, bp
mov cx, 0x0100
rep movsw              ;move boot code to the 0x1FE0:0x0000
jmp 0x1FE0:cont

loadseg_off dw 0
loadseg_seg dw 0x0060

cont:
mov ds,ax
mov ss,ax
lea sp,[bp-0x20]
sti

mov [drive],dl ;BIOS passes drive number in DL

main16:

call LoadStage2
cmp [errorflag],0

jg hang16
;jmp testinstead16
jmp loadpoint16 ;jump to loaded program

hang16:
xor ah,ah
int 0x16             ; wait for a key
int 0x19             ; reboot the machine

LoadStage2:
  pusha
  mov [counter1],1
  .tryread:
    mov ax,ds          ;segment
    mov es,ax
    mov bx,loadpoint16 ;offset
    mov ah,02h         ;read sectors into memory
    mov al,4d          ;load 4 sectors
    mov ch,00h         ;the track to read from
    mov cl,02h         ;sector id
    mov dh,00h         ;head
    mov dl,[drive]     ;drive
    int 13h
    jc .tryagain
    jmp .fin
  .tryagain:
    inc [counter1]
    cmp [counter1],3
    jg .failed
    jmp .tryread
  .failed:
    mov [errorflag],1
  .fin:
  popa
ret

drive db 0

xpos db 0
ypos db 0

errorflag db 0
counter1 db 0

ascii db 0x10
times 510-($-$$) db 0

dw 0xAA55
;end of stage 1 boot
;=========================================
;stage 2 boot
loadpoint16:cli

call LoadGDT
call EnableA20
call ReloadSegments

jmp Start32

gdtr:
 dw 0 ;for limit storage
 dd 0 ;for base storage
gdt:
 dq 0                   ;dummy entry (8 zero filled bytes)
;gdt code:              ;code descriptor
 dw 0xFFFF              ;limit low
 dw 0                   ;base low
 db 0                   ;base middle
 db 10011010b           ;access
 db 11001111b           ;granularity
 db 0                   ;base high
;gdt data:              ;data descriptor
 dw 0xFFFF              ;limit low
 dw 0                   ;base low
 db 0                   ;base middle
 db 10010010b           ;access
 db 11001111b           ;granularity
 db 0                   ;base high
gdt_end:

LoadGDT:
 mov eax, [esp + 4]
 mov [gdtr + 2], eax
 mov ax, [esp + 8]
 mov [gdtr], ax
 lgdt [gdtr]
ret

EnableA20:
 in al,0x92
 test al,2
 jnz .fin
 or al,2
 and al,0xFE
 out 0x92,al
 .fin:
ret

ReloadSegments:
 jmp 0x08:reload_CS     ;0x08 points at the new code selector
 reload_CS:
 mov ax,0x10            ;0x10 points at the new data selector
 mov ds,ax
 mov es,ax
 mov fs,ax
 mov gs,ax
 mov ss,ax
ret

;end of stage 2 boot
;=========================================
;stage 3 boot
use32
Start32:

hang32:
jmp hang32

End32:
;end of stage 3 boot
my head hurts >.< halp!
User avatar
Minoto
Member
Member
Posts: 89
Joined: Thu May 12, 2011 7:24 pm

Re: far jmp after enabling A20 triple faults

Post by Minoto »

TwixEmma wrote: LoadGDT:
mov eax, [esp + 4]
mov [gdtr + 2], eax
mov ax, [esp + 8]
mov [gdtr], ax
lgdt [gdtr]
ret
This appears to expect to find the base and limit of your GDT on the stack, yet I don't see you doing anything that would put them there...
Those who understand Unix are doomed to copy it, poorly.
Casm
Member
Member
Posts: 221
Joined: Sun Oct 17, 2010 2:21 pm
Location: United Kingdom

Re: far jmp after enabling A20 triple faults

Post by Casm »

rep movsw ;move boot code to the 0x1FE0:0x0000
You won't do that with es:di = 0x1FE0:0x7C00
Last edited by Casm on Fri Jul 19, 2013 3:56 pm, edited 1 time in total.
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: far jmp after enabling A20 triple faults

Post by AJ »

TwixEmma wrote:
DavidCooper wrote:What is this?

Code: Select all

;enable A20
mov eax,cr0
or eax,1
mov cr0,eax
jmp 0x8 ;this triple faults
That code doesn't enable the A20
...
p.s. A20 is enabled by that code, it's probably not the best way of doing it though.
That code absolutely does not enable A20. One of the fundamental problems, however, is that your jump is not a far jump as has also been pointed out. Please read the existing replies more carefully and do some more research. You may find that after you are in PMode you do then stumble across A20 related problems but your code has not yet reached that point.

Cheers,
Adam
Casm
Member
Member
Posts: 221
Joined: Sun Oct 17, 2010 2:21 pm
Location: United Kingdom

Re: far jmp after enabling A20 triple faults

Post by Casm »

AJ wrote:That code absolutely does not enable A20. One of the fundamental problems, however, is that your jump is not a far jump as has also been pointed out.
On closer inspection, that jump does make some sort of sense. If the rep movsw had successfully copied his code to 0x1FE0:0000, then the offset address of the label in the new segment would be the same as that in the old segment. Or at least it would it he didn't org it at 0x7c00. It might work if he had ds = 0x7C0, si = 0 and org 0. At the entry point to his code, he might also need to do a far jump from 0000:0x7C00 to 0x07C0:0x0005 (not sure about that).
linguofreak
Member
Member
Posts: 510
Joined: Wed Mar 09, 2011 3:55 am

Re: far jmp after enabling A20 triple faults

Post by linguofreak »

TwixEmma wrote:
iansjack wrote:You don't do a far jump to the 32-bit code; you do a near jump to 0x7c08.
Thanks for your reply but I believe you're missing the point, I tried your suggestion but it still triple faults. I move the 32bit code to 0x0000:0x0000
so 0x7C08 points to where?
What he means to say is that your code, as written, does not do a far jump to the 32-bit code, but rather makes a near jump to CS:0008 (which is 0x7C08 physical).

"jmp 0x8" should be "jmp 0x8:0", given the entry point you state for your 32-bit code.

@iansjack: "You don't do a far jump" in English implies "you aren't supposed to do a far jump". What you meant to say is "You aren't doing a far jump".
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: far jmp after enabling A20 triple faults

Post by iansjack »

linguofreak wrote:@iansjack: "You don't do a far jump" in English implies "you aren't supposed to do a far jump". What you meant to say is "You aren't doing a far jump".
I don't think that is true. :wink: (But I do appreciate the potential ambiguity.)
Mikemk
Member
Member
Posts: 409
Joined: Sat Oct 22, 2011 12:27 pm

Re: far jmp after enabling A20 triple faults

Post by Mikemk »

iansjack wrote:
linguofreak wrote:@iansjack: "You don't do a far jump" in English implies "you aren't supposed to do a far jump". What you meant to say is "You aren't doing a far jump".
I don't think that is true. :wink: (But I do appreciate the potential ambiguity.)
I don't know about British English, but it's true in American English
Programming is 80% Math, 20% Grammar, and 10% Creativity <--- Do not make fun of my joke!
If you're new, check this out.
Post Reply