I want to output the RTC date.
I realized that I had to convert from BCD to ASCII in order to do that, but I do not know what to do.
To convert, I use this page: BCD to ASCII conversion, but it uses interrupt 21h and in this page: https://en.wikipedia.org/wiki/BIOS_interrupt_call interrupt 21h does not exist.
How can I convert and print BCD?
DAY:
mov ah,0x04
int 0x1a
mov al,dl
aam ;to convert.
mov bx,ax
mov cx,ax
add dl,ch
mov ah,02h
int 21h
mov dl,cl
int 21h
I tested the code in ubuntu. I think I should use interrupt 10h for output and not 21h. (int 21h
is not active).
So, how to convert BCD to ASCII, and how to print it using interrupt 10h?
Just use following style?
mov al, 'h'
int 10h
What is BCD (binary-coded decimal)?
In case of the BIOS time interrupt result, the "packed BCD" is used. Each byte (8 bits) is split into two halves of 4 bits (nibbles), each containing one decimal value (4 bits allow for 0-15 values, but only 0-9 values are used to stay "decimal").
So for example if the time is ending with "37" seconds, the seconds byte will contain value
0x37 = 55 = 0b00110111
. Notice how both in hexadecimal and binary the 4-bit halves are visible/readable even by human after short practice (in decimal not, you have to calculate in head the division/remainder by 16 to split it into 3 and 7:55 / 16 = 3
,55 % 16 = 7
).Now assembly is pretty straightforward with bit fiddling, so even if you don't want to delve into the specialized BCD instructions like
AAM
, you can use ordinary bit masking + shifting to extract the two values.Let's say you have value
0x37
inBL
, and you want to extract it intoBH
(0x03
) andBL
(0x07
), then for example this code will calculate that:How to display it?
That depends on your target platform, judging from question and comments you are aiming for x86 16b real mode on PC compatible computer with only BIOS available, so one of the easiest ways is to convert those decimal 0-9 values into ASCII values of digits (adding 48 works, or many assemblers will do conversion from chars for you, so for example
add bl,'0'
works, and you can think about it as "add font character 0 to 0-9 value", and as the next digits in font are defined in +1 way from'0'
, it will calculate the correct character value).And then use one of the
int 10h
services to display the ASCII character, like theAH=0x0A
service. Example of displaying the ASCII character fromBL
:As you want to display the time, and you have the values in several registers, you will probably need to preserve them between printing, for example, if I would use
int 0x1A,02
service to read RTC, I would use this "architecture" to display it (not writing full implementation, just the top logic to show you how you can usepush/pop
stack instructions to preserve values for later usage):Now I will comment on some of your problems in comments:
Yes, that's not legal, because
ax
is 16 bit register, andcl
is 8 bit register (alias for lower 8b part ofcx
), so you would lose 8 bits in such operation.To show as programmer that you indeed do want to lose the upper 8 bits, you can write
mov cl,al
(al
is alias of lower 8 bits ofax
).The opposite conversion like
mov ax,cl
will again fail, but again as a programmer you can define precisely, how the 8 bit value should be converted into 16 bits value.For example to do "unsigned" conversion you can use either the 386+ instruction:
Or 8086-80286 calculation way:
And for "signed" conversion there's again specialized 386+ way:
Just keep in mind the computer is a bit more complex calculator, nothing else, so you should try to convert from the word task into thinking which numerical values you have on the input side, what numeric values represent output side (even "characters" are just numeric values in computer), and then you just figure out mathematical formulas to convert the input numbers into output numbers.
If you have bochs, comment out code which does not compile yet, and start with small chunk of code which works, check in debugger what they are doing, so you can visually see how the calculation is going on, then add slowly new parts of code by 2-3 instructions, and keep running them in debugger to see if they calculate what you want. (the overuse of word "calculate" in recent paragraphs is intentional.. if you know how to operate the calculator, you are pretty close to know how to code in assembly, although your initial source will be probably ugly, as it takes time to pick up also "style" and efficiency - just check the instruction set to understand what kind of calculations are possible and get better insight into what means that
AX
is 16 bit register, andAL
is 8 bit, and how the numeric values are encoded in bits (electricity current)).Not exactly, you ran just
nasm
in ubuntu to produce 16bit x86 machine code binary (cross-compiling, you can produce such binary on any other machine, which has x86 assembler, not really relevant to your questions, except you should specify NASM, so people trying to answer you will know which x86 assembly syntax to use, each assembler has tiny differences). Then you did try that binary in virtual machine (BOCHS). If you would try to run it directly under ubuntu, it would fail completely, as ubuntu OS doesn't support runtime environment for 16b real mode machine code.When unsure what is relevant, just describe all of your tools, and command lines/options you use.