Ok i figured out how to redo the macros(I think). but when i run the last bit of code i get "error: expression syntax error"
Also... How would I go about storing these values in memory(RAM) so I don't take up space in my program reserving bytes... this is in a bootloader so I know i only got about 1MiB or so.
%macro siprint 1 ;screen interrupt print
mov  si, %1 ;move text into SI
call print_string
%endmacro
%macro add_crlfterm 2 ;string, length(start of offset)  adds CR+LF+null terminator
mov [%1+%2], 13
mov [%1+%2+1], 10
mov [%1+%2+2], 0x00
%endmacro

%macro add_crlf_and_print 2  ;combine the two above functions
add_crlfterm %1, %2
siprint %1
%endmacro
cpustring resb 15 ;reserve 15 bytes... 12 for cpuid, 3 for crlf and null terminator
            mov eax, 0x00 ;Set CPUID Parameter

xor ebx, ebx ;Clear Output
xor edx, edx
xor ecx, ecx

CPUID ;Call CPUID

mov dword , ebx      ;Throw output into the string
mov dword , edx
mov dword , ecx

            add_crlf_and_print , 12; Print CPUID to screen
Posted on 2009-10-29 00:02:06 by Goose007
You're getting an expression syntax error because you're code is generating an invalid syntax. When we hand process the code it looks like this.

	mov [+12], 13
mov [+12+1], 10
mov [+12+2], 0x00
mov  si, ;move text into SI
call print_string


That's not right by any means. Try using 'add_crlf_and_print cpustring, 12' instead. In NASM the label alone will decode to the address whereas the label enclosed in brackets expands to the "value of". You're wanting to use the address so you need to drop the brackets to generate.

	mov , 13 ; ADDRESS + 12 = CR
mov , 10 ; ADDRESS + 12 + 1 = LF
mov , 0x00 ; ADDRESS + 12 + 2 = NULL Terminator
mov  si, cpustring ;move the ADDRESS of text into SI
call print_string
Posted on 2009-10-29 00:21:43 by Synfire
lol well i changed it now I get a different error for the same line. I should have used NASM in the first place... I feel like i learned everything backwards using FASM for to long.

add_crlf_and_print cpustring, 12


"operation size not specified"
Posted on 2009-10-29 00:34:35 by Goose007
NASM, by design, chooses not to remember the types of variables you declare. Whereas MASM will remember, on seeing var dw 0, that you declared var as a word?size variable, and will then be able to fill in the ambiguity in the size of the instruction mov var,2, NASM will deliberately remember nothing about the symbol var except where it begins, and so you must explicitly code mov word ,2.
Posted on 2009-10-29 01:35:42 by baldr
baldr: Thanks alot. As far as resb and such, how would I go about saving this info in a specific address in RAM instead of adding the 15 reserved bytes to my code? like say I wanted to put it at an address not it use... like 0x8000:0x0000 and write to it kinda like

%define cpustring 0x8000:0x0000


this way I'm only adding 4 bytes to my app instead of 15... and since this seems to happen alot. I'd be saving alot more space the further along I go. how would I own this memory space? or do i not even need to worry about that till I write my malloc and free functions.

Sorry I have 5 or 6 books on the way from Amazon(well some used books take forever to ship, but I can't complain cuz I got it for $0.15 and 4$ shipping for one of them) and I'm just a bit anxious.
Posted on 2009-10-29 08:52:51 by Goose007
One thing you could do is put your cpuinfo buffer in "section .bss". There are no "segments" in a flat binary file, of course. What Nasm does (acting as its own linker), is put "section .text" first, followed by "section .data", with "section .bss" last - this doesn't add anything to your file, Nasm just assigns numbers to your labels. You want this *after* your padding and boot signature...

section .text
jmp short overBPB
nop
; your boot/bios parameter block
overBPB:
; set up segment registers!!!
; your code
times 510 - ($ - $$) db 0
db 55h, 0AAh ; or 0AAh, 55h... been a while... :)
section .bss
cpuinfo resb 13
; etc...

You could also put it at a specific segment:offset, but this would involve manipulating segment registers (ds). You probably don't want to do that. Why do you want to do cpuid in a bootsector anyway? Space is tight! Concentrate on loading something else (your "second stage", probably) - the only thing a bootsector is good for (IMO)...

Best,
Frank

Posted on 2009-10-29 12:34:32 by fbkotler
Lol sorry this is in the second stage, but that's besides what i was really wanting to know... I have tried the following

             mov bx, 0200h
mov ds, bx

mov eax, 0x00 ;Set CPUID Parameter

xor ebx, ebx ;Clear Output
xor edx, edx
xor ecx, ecx

CPUID ;Call CPUID

mov , ebx ;mov , ebx
mov , edx ;mov , edx
mov , ecx ;mov , ecx

call tstfunc
call EOF

tstfunc:
push ax                  ; save Ax register
push bx                  ; and the rest of them too
push cx
push dx
push ds                  ; ditto DS
MOV BX,0200h            ; segment              
MOV DS,BX              
MOV BX,00h            ; offset                
MOV AH,0x0E                ;Print function for int 10
MOV CX,12              ; print 12 characters
            .print_it:        
MOV AL,           ; move char into AL to print it                
INT 10h                  ; print char              
INC BX                   ; increment BX by 1              
loop .print_it
pop ds                   ; restore DS
pop dx
pop cx
pop bx
pop ax                   ; restore registers
ret      



this works, but when i try to make it a macro it doesn't...

%macro write_to_memory	3
PUSH AX ;Push registers
PUSH BX
PUSH DS ;And data segment
MOV BX, %1 ;Which segment to write to
MOV DS, BX ;Move it to the data segment
MOV BX, %2 ;Which offset are we writing to
MOV , %3 ;Write third parameter to destination (data to memory)
POP DS
POP BX
POP AX
RET
%endmacro
write_to_memory 0200h, 0000h, ebx
...
call testfunc


I assume this has to do withthe fact that i'm setting BX when that's what I'm reading from. but it doesn't seem to work for the other registers either..
Posted on 2009-10-29 20:21:46 by Goose007
Possible problem... int 10h/0Eh sometimes uses bh for video "page" and bl for color/attribute - depends on bios. If substituting si (or di) for bx doesn't help, that's not it. (sorry... you said that *did* work...)

Your macro expands (in part) to:

mov , ebx

That's probably not "right", but you should get two characters out of it... and you said edx/ecx didn't work either... Since your macro ends in "ret", you ought to be "call"ing it. Could that be it?

... and you say this *is* the "second stage"... Jeez, I'm batting 000 here! If that call/ret doesn't help, I'm stumped, I guess!

Best,
Frank

Posted on 2009-10-29 22:10:15 by fbkotler
lol sorry my mind is scrambled... just found out me and my wife are having a baby the other day. I haven't been exactly .... paying as much attention to this as I was originally planning on at the moment. trying to learn ASM when you're thinking about other things in the background can be detrimental to your coding... i even typed "crib" on a line when she came in and asked me a question... wierd... anyway enough rambling... I will try it out in about 30 minutes when i get to my ASM machine.
Posted on 2009-10-29 22:27:10 by Goose007
WOW!!! I can't believe i left RET in the macro... my final macro looks like this

%macro write_to_memory	3
PUSH DS
PUSH BX
MOV BX, %1 ;Which segment to write to
MOV DS, BX ;Move it to the data segment
POP BX                                  ;Restore BX in case we're reading from it
MOV SI, %2 ;Which offset are we writing to
MOV , %3 ;Write third parameter to destination (data to memory)
POP DS
%endmacro


OK I'm still trying to remember the use for each of the registers(I know i've been using them incorrectly)... I have been reading the Intel manual... till my books get here anyway. Thanks for pointing that out for me fbkotler!!
Posted on 2009-10-29 22:40:24 by Goose007
Don't forget that your macro uses si as a scratch register (write_to_memory 0x2000, 0, si will write 0 to [0x2000:0] regardless of the si value upon invocation, for example).

You can use 32-bit code in 16-bit code easily, just don't forget about segment limits of 0xFFFF (or you will get #PF). Here is the example:


        mov    eax, 80*25-2            ; op-size override prefix (66) here
        push    0xb800
        pop    es
        mov    dword , 0x1400+'X'+0x14000000+'Y'*0x10000; op-size and addr-size override prefixes (67 66) here


This puts red 'XY' on blue background in lower right corner of 80*25 text screen.
Posted on 2009-10-30 02:02:27 by baldr
First, congratulations to you and "Mrs. Goose007" :) Having a child *will* distract you from learning asm - and a bunch of other things!

Don't worry too much about "misusing" registers. Don't overwrite ones you're "using", of course.  They're called "general purpose" registers (not segment registers - they're quite different!). In 16-bit code, memory references are limited to bx, si, di, and bp. Some registers are implied operands to certain instructions, so they aren't entirely "created equal", but mostly you can use 'em as you wish. As Baldr points out, you can use 32-bit registers in 16-bit code, so "mov al, " will work, but "mov al, " won't. The former requires an "address override prefix" (67h) - Nasm will emit that automatically. The total offset must be within the 16-bit limit of 0FFFFh. There's a "trick" to get around that, but don't worry about it yet.

If I can make a couple of suggestions, you don't need to clear ebx, ecx, and edx before "cpuid" - they'll be overwritten anyway. Your "write_to_memory" macro isn't the most "efficient" way to do it. Might be better to do something like:

push ds
push 200h
pop ds ; or go through another register - "mov ds, 200h" won't work
mov si, 0 ; ? if that's what you want
call get_vendor_string
; maybe call your "print" function before restoring ds?
pop ds
...

...
get_vendor_string:
xor eax. eax
cpuid
mov , ebx
mov , edx
mov , ebx
; mov word , 0A0Dh for CR/LF, if you want - bigger buffer!
ret

At this point, eax will contain the "maximum level" supported by cpuid - doing cpuid with a larger value will give confusing results (my Pentium IV reports 16 cores, if I ask it that!). There's an exception to that... if eax=8000000h works, you can get a longer "cpuname" string, including Hz, using eax = 8000001h, 80000002h, etc. This is for Linux, but could be converted to your environment easily:

global _start

section .bss
    namestring resb 48

section .text
_start:

    mov eax, 80000000h
    cpuid
    cmp eax, 80000004h
    jb exit ; bail out if not supported
   
    mov edi, namestring

    mov eax, 80000002h
    cpuid
    call savestring

    mov eax, 80000003h
    cpuid
    call savestring

    mov eax, 80000004h
    cpuid
    call savestring

; print the string
    mov ecx, namestring
    mov edx, 48
    mov ebx, 1
    mov eax, 4
    int 80h

exit:
    mov eax, 1
    int 80h

savestring:
    stosd
    mov eax, ebx
    stosd
    mov eax, ecx
    stosd
    mov eax, edx
    stosd
    ret

I don't know if that will help you, but I recently discovered it and I think it's kinda "cool". You probably will eventually want to "capture" the info for later use, rather than printing it.

Best,
Frank

Posted on 2009-10-30 15:44:11 by fbkotler