2

Ok first of all, I know that if i have a 8 bit computer it can only handle 8 bit numbers, not higher than 8, but I know that it is still possible to represent a 16-bit number or even a 32,64,128-bit number by allocating more memory in ram. But for the sake of simplicity lets just use a 16 bit number as an example.

Let's say we have a 16 bit number in ram like this:

12 34 <-- That's Hexadecimal btw

Let's also write it in binary just in case yall prefer binary form:

00010010 00110100 <-- Binary
              &
      4660 in decimal

Now, we know that the computer cant understand this big number(4660) as one single number, because the computer can only understand 8-bit numbers which only goes up to 255. So the byte on the right would stay as it is:

00110100 <-- 52 in decimal

but the left byte:

00010010 <-- would be 18 if it was the byte on the right, 
             but since it is on the left, it means that its
             4608 

So my question is, how does the computer read the second byte as 4608 if it can only understand numbers that are lower than 255, and then after that how does it interprets those two bytes as a single number(4660)?

Thanks, if you are confused feel free to ask me down in the comments. I made it as clear as possible.

CosnotraLF
  • 55
  • 8
  • 6
    It's better if you try not to think of the computer as "understanding" anything except its instruction set. An 8-bit computer has instructions for reading bytes, mixing them up in various ways, and writing bytes. The values of those bytes only become numbers in your head. What you want to ask is "how can I add/subtract/multiply/divide" numbers > 256 if I only have single-byte instructions? In school you were taught how to calculate with large numbers even though you only remember the tables for single-digit addition and multiplication. – Matt Timmermans Dec 28 '16 at 19:01
  • So it's the same..? – CosnotraLF Dec 29 '16 at 03:12
  • Can u give an example using binary and actual code.. Pseudo is fine w me. – CosnotraLF Dec 29 '16 at 03:27

2 Answers2

4

well this is more programing question then HW architecture as the CPU only does 8bit operations in your test case and has no knowledge about 16bit. Your example is: 16bit arithmetics on 8bit ALU and is usually done by splitting to High and Low half of number (and joining latter). That can be done in more ways for example here few (using C++):

  1. transfer

    const int _h=0; // MSB location
    const int _l=1; // LSB location
    BYTE h,l; // 8 bit halves
    WORD hl;  // 16 bit value
    h=((BYTE*)(&hl))[_h];
    l=((BYTE*)(&hl))[_l];
    // here do your 8bit stuff on h,l
    ((BYTE*)(&hl))[_h]=h;
    ((BYTE*)(&hl))[_l]=l;
    

    You need to copy from/to the 8bit/16bit "register" copies which is slow but sometimes can ease up things.

  2. pointers

    const int _h=0; // MSB location
    const int _l=1; // LSB location
    WORD hl;  // 16 bit value
    BYTE *h=((BYTE*)(&hl))+_h;
    BYTE *l=((BYTE*)(&hl))+_l;
    // here do your 8bit stuff on *h,*l or h[0],l[0]
    

    you do not need to copy anything but use pointer access *h,*l instead h,l. The pointer initialization is done just once.

  3. union

    const int _h=0; // MSB location
    const int _l=1; // LSB location
    union reg16 
     {
     WORD dw;  // 16 bit value
     BYTE db[2]; // 8 bit values
     } a;
    // here do your 8bit stuff on a.db[_h],a.db[_l]
    

    This is the same as #2 but in more manageable form

  4. CPU 8/16 bit registers

    Even 8 bit CPU's have usually 16 bit registers accesible by its half or even full registers. For example on Z80 you got AF,BC,DE,HL,PC,SP most of which are directly accessible by its half registers too. So there are instructions working with hl and also instructions working with h,l separately. On x86 it is the same for example:

    mov AX,1234h
    

    Is the same (apart of timing and possibly code length) as:

    mov AH,12h
    mov AL,34h
    

Well that is conversion between 8/16 bit in a nutshell but I assume you are asking more about how the operations are done. That is done with use of Carry flag (which is sadly missing from most of higher languages then assembler). For example 16 bit addition on 8 bit ALU (x86 architecture) is done like this:

// ax=ax+bx
add al,bl
adc ah,bh

So first you add lowest BYTE and then highest + Carry. For more info see:

For more info about how to implement other operations see any implementation on bignum arithmetics.

[Edit1]

Here small C++ example of how to print 16 bit number with only 8 bit arithmetics. You can use 8 bit ALU as a building block to make N*8 bit operations in the same way as I did the 16 bit operations ...

//---------------------------------------------------------------------------
// unsigned 8 bit ALU in C++
//---------------------------------------------------------------------------
BYTE cy;                    // carry flag cy = { 0,1 }
void inc(BYTE &a);          // a++
void dec(BYTE &a);          // a--
BYTE add(BYTE a,BYTE b);    // = a+b
BYTE adc(BYTE a,BYTE b);    // = a+b+cy
BYTE sub(BYTE a,BYTE b);    // = a-b
BYTE sbc(BYTE a,BYTE b);    // = a-b-cy
void mul(BYTE &h,BYTE &l,BYTE a,BYTE b);    // (h,l) = a/b
void div(BYTE &h,BYTE &l,BYTE &r,BYTE ah,BYTE al,BYTE b);   // (h,l) = (ah,al)/b ; r = (ah,al)%b
//---------------------------------------------------------------------------
void inc(BYTE &a) { if (a==0xFF) cy=1; else cy=0; a++; }
void dec(BYTE &a) { if (a==0x00) cy=1; else cy=0; a--; }
BYTE add(BYTE a,BYTE b)
    {
    BYTE c=a+b;
    cy=DWORD(((a &1)+(b &1)   )>>1);
    cy=DWORD(((a>>1)+(b>>1)+cy)>>7);
    return c;
    }
BYTE adc(BYTE a,BYTE b)
    {
    BYTE c=a+b+cy;
    cy=DWORD(((a &1)+(b &1)+cy)>>1);
    cy=DWORD(((a>>1)+(b>>1)+cy)>>7);
    return c;
    }
BYTE sub(BYTE a,BYTE b)
    {
    BYTE c=a-b;
    if (a<b) cy=1; else cy=0;
    return c;
    }
BYTE sbc(BYTE a,BYTE b)
    {
    BYTE c=a-b-cy;
    if (cy) { if (a<=b) cy=1; else cy=0; }
    else    { if (a< b) cy=1; else cy=0; }
    return c;
    }
void mul(BYTE &h,BYTE &l,BYTE a,BYTE b)
    {
    BYTE ah,al;
    h=0; l=0; ah=0; al=a;
    if ((a==0)||(b==0)) return;
    // long binary multiplication
    for (;b;b>>=1)
        {
        if (BYTE(b&1))
            {
            l=add(l,al);    // (h,l)+=(ah,al)
            h=adc(h,ah);
            }
        al=add(al,al);      // (ah,al)<<=1
        ah=adc(ah,ah);
        }
    }
void div(BYTE &ch,BYTE &cl,BYTE &r,BYTE ah,BYTE al,BYTE b)
    {
    BYTE bh,bl,sh,dh,dl,h,l;
    // init
    bh=0; bl=b; sh=0;   // (bh,bl) = b<<sh so it is >= (ah,al) without overflow
    ch=0; cl=0; r=0;    // results = 0
    dh=0; dl=1;         // (dh,dl) = 1<<sh
    if (!b) return;     // division by zero error
    if ((!ah)&&(!al)) return;   // division of zero
    for (;bh<128;)
        {
        if (( ah)&&(bh>=ah)) break;
        if ((!ah)&&(bl>=al)) break;
        bl=add(bl,bl);
        bh=adc(bh,bh);
        dl=add(dl,dl);
        dh=adc(dh,dh);
        sh++;
        }
    // long binary division
    for (;;)
        {
        l=sub(al,bl);   // (h,l) = (ah,al)-(bh,bl)
        h=sbc(ah,bh);
        if (cy==0)      // no overflow
            {
            al=l; ah=h;
            cl=add(cl,dl);  // increment result by (dh,dl)
            ch=adc(ch,dh);
            }
        else{           // overflow -> shoft right
            if (sh==0) break;
            sh--;
            bl>>=1;     // (bh,bl) >>= 1
            if (BYTE(bh&1)) bl|=128;
            bh>>=1;
            dl>>=1;     // (dh,dl) >>= 1
            if (BYTE(dh&1)) dl|=128;
            dh>>=1;
            }
        }
    r=al;       // remainder (low 8bit)
    }
//---------------------------------------------------------------------------
// print 16bit dec with 8bit arithmetics
//---------------------------------------------------------------------------
AnsiString prn16(BYTE h,BYTE l)
    {
    AnsiString s="";
    BYTE r; int i,j; char c;
    // divide by 10 and print the remainders
    for (;;)
        {
        if ((!h)&&(!l)) break;
        div(h,l,r,h,l,10);  // (h,l)=(h,l)/10; r=(h,l)%10;
        s+=char('0'+r);         // add digit to text
        }
    if (s=="") s="0";
    // reverse order
    i=1; j=s.Length();
    for (;i<j;i++,j--) { c=s[i]; s[i]=s[j]; s[j]=c; }
    return s;
    }
//---------------------------------------------------------------------------

I use VCL AnsiString for text storage you can change it to what ever string or even char[] instead. You need to divide the whole number not just the BYTE's separately. See how the div function works. Here example of least significant digit of 264 print 264%10...

a = 264 = 00000001 00001000 bin
b =  10 = 00000000 00001010 bin
d =   1 = 00000000 00000001 bin
// apply shift sh so b>=a 
a = 00000001 00001000 bin
b = 00000001 01000000 bin
d = 00000000 00100000 bin
sh = 5
// a-=b c+=d while a>=b
// a<b already so no change
a = 00000001 00001000 bin b = 00000001 01000000 bin c = 00000000 00000000 bin d = 00000000 00100000 bin
// shift right
b = 00000000 10100000 bin d = 00000000 00010000 bin sh = 4
// a-=b c+=d while a>=b
a = 00000000 01101000 bin c = 00000000 00010000 bin
// shift right
b = 00000000 01010000 bin d = 00000000 00001000 bin sh = 3
// a-=b c+=d while a>=b
a = 00000000 00011000 bin c = 00000000 00011000 bin
// shift right
b = 00000000 00101000 bin d = 00000000 00000100 bin sh = 2
b = 00000000 00010100 bin d = 00000000 00000010 bin sh = 1
// a-=b c+=d while a>=b
a = 00000000 00000100 bin c = 00000000 00011010 bin
// shift right
b = 00000000 00001010 bin d = 00000000 00000001 bin sh = 0
// a<b so stop a is remainder -> digit = 4
//now a=c and divide again from the start to get next digit ...
Community
  • 1
  • 1
Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Thx bro this answer was really helpful +1 – CosnotraLF Dec 29 '16 at 14:57
  • But ok if it's an 8 bit alu. How would it print this 16 bit number on screen. I know it's pretty easy to print it as a hex number because it would just have to print or store the values of ah and al in memory and then print them out later. But how would it convert this big 16 bit number that the computer can't understand as 1 big number because it only reads information byte per byte so if the 16 bit number was 01 A0, which is 416 in decimal and the highest number a 8 bit computer can understand is 255. So then how would the computer print out this number if its out of its knowledge capability – CosnotraLF Dec 29 '16 at 15:09
  • @CosnotraLF easily you just continuously divide by 10 in 16 bit arithmetics made from 8 bit operations ... printing the remainders in reverse order. The `div` and `mod` operations can be converted to set of `+,-` operations which are easily implementable. For faster methods use binary division (using shifts and substractions for div and shift and add for mul and or radix approaches...) for more info see [bigint hex/dec conversion in C++](http://stackoverflow.com/a/18231860/2521214) – Spektre Dec 29 '16 at 20:20
  • @CosnotraLF the best book on this topic I read in my lifetime is this [Assembler a ZX Spectrum](https://cs.wikipedia.org/wiki/Assembler_a_ZX_Spectrum) but it is in Czech (not sure if any English translations exists) It covers 8bit arithmetics use for 16 bit operations, printing numbers, handling IO and gfx at Low Level and more. here PDF versions: [1st part](http://zxm.speccy.cz/dok/lit/ASMaZX1.pdf) and [2nd part](http://zxm.speccy.cz/dok/lit/ASMaZX2.pdf) – Spektre Dec 29 '16 at 20:32
  • @CosnotraLF btw to ease up base 10 operations and printing you can use BCD (binary coded decimal) code ... most CPU's x86 included have instruction support for this number format... – Spektre Dec 29 '16 at 20:37
  • Thx specktre! Ur awesome!! Now it makes more sense... I would give u +10000 votes but I can't lol.. So I'll just mark it as the best answer! Thx again.. – CosnotraLF Dec 30 '16 at 00:19
  • Lol let me ask u sumthin... its it hard Thoe? Is it hard to divide the a 16 bit number when the ALU can only perform 8 but division bcs i get what ur saying but idk how it would handle a 16 bit num bcs ok let's say I have the decimal number 16, 0001 0000 in binary. If I divide 16 by 10 the remainder would BE 6 and the quotioent would be 1. So now 1/16, the remainder would BE 1 and the quotient, 0. So now if we print the remainders to tha screen it would look like this: 16 which is right.... But let's say we have a number greater than 8 bits.... – CosnotraLF Dec 30 '16 at 01:32
  • Continuation.... Let's say we have the decimal 264, 0000 0001 0000 1000 in binary. When we divide the first 8 bits on the right. You get 8 right because ok imma do the math as u said.. 8/10 remainder would be 8 and quotient 0. And we print the ONLY the remainders for the first 8 bits( the ones on the right ) and its just 8.. Ok now we move to the next byte(aka 8 bits)( the ones on the left ). And since the computer don't know it's 256, it's just gonna understand it as a 0000 00001 or 1 in decimal. So when it tries to divide 1 by 10 the remainder is gonna be 1 and the quotient, 0.... – CosnotraLF Dec 30 '16 at 01:44
  • Continuation part 2...So when it tries to print both remainders to the screen... It's gonna be 18.. And that's not right because the number we are trying to get is 264... U get what I'm saying lol sorry I'm bad at expressing myself... But can u help me out with this bcs I'm trynna make a 8 bit computer.. Out of pure 7400s.. Nothing complex just simple gates.. – CosnotraLF Dec 30 '16 at 01:49
  • 1
    @CosnotraLF added [edit1] with the 264 example and simple C++ code to do it ... You do not need to make a big deal of this first you need to make sure 8bit stuff works as should and only then worry about programing higher stuff. Just make sure your ALU have all the functions you need (+,-,inc,dec,AND,OR,XOR,SHL,SHR,ROL,ROR) and flags `Z,S,CY,AC` the rest can be done with microcode in your control unit ... – Spektre Dec 30 '16 at 11:34
  • thx I get it now!! Ur really smart btw nd I wish I could read that book that u were taking about but I can't seem to find any English translations of it... Do u recommend another one that's almost like that one but in English? – CosnotraLF Dec 30 '16 at 13:57
  • @CosnotraLF do not know of any but try to look for anything related to ZX Spectrum and programing .... From fast google search this looks promising: http://rvbelzen.tripod.com/z80prgtemp/z80prg03.htm there must be tons of tutorials for zilog. – Spektre Dec 30 '16 at 14:06
  • @CosnotraLF this [What's the proper implementation for hardware emulation?](http://stackoverflow.com/a/18911590/2521214) may shine some light into the micro code encoding and instruction timing... see my instruction set link in there. You could encode you instructions in similar way into some ROM which will be used as a code for control unit inside your CPU – Spektre Dec 30 '16 at 14:13
0

By interpreting them as base-256.

>>> 18*256 + 52
4660
David Eisenstat
  • 64,237
  • 7
  • 60
  • 120