Confusion About Column Indexing and Bit Selection in Display Unit Graphic (Module 4.5)

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Confusion About Column Indexing and Bit Selection in Display Unit Graphic (Module 4.5)

BigBang
This post was updated on .
I have a little confusion. In the video course (Module 4.5), a graphic of the display unit is shown (at minute 5:15). This map starts counting from column 0 - 511.

The calculation "col % 16" is used to determine the bit.

If I want to select the first pixel in a row (column 0) and enter a 0 for col in the calculation "col % 16", the result tells me that I should select the 0th bit. There is no bit 0 in a RAM register.

But there is a word 0 and a row 0.

For example, the first pixel in the top left corner cannot be selected with row 0 and col 0. Instead, row 0 and col 1 must be selected.

Example A (row = 0, col = 0)
word: 0 x 32 + 0 / 16 = 0
bit: 0 % 16 = 0

Example B (row = 0, col = 1)
word: 0 x 32 + 1 / 16 = 0
bit: 1 % 16 = 1

So that the calculation "row x 32 + col / 16" works, there are rows 0 - 255.

But the columns in the calculation "row x 32 + col / 16" and "col % 16" are given from 1-512? Is that correct?
Reply | Threaded
Open this post in threaded view
|

Re: Confusion About Column Indexing and Bit Selection in Display Unit Graphic (Module 4.5)

dolomiti7
I'll try to summarize the logic of the Hack computer screen
- Resolution of 512x256 pixels (512 columns in horizontal(x)-direction and 256 rows in
  vertical(y) direction)
- Each pixel can be either white or black (1 bit "color" depth)
- The required video RAM is therefore 512x256x1=131,072 bits=16,384 bytes=8,192 16-bit words
  (hereinafter called "word" or "words").
- The address space of the Hack computer is organized in 16-bit words, e.g. each address corresponds to
  one word (there are no individual bytes)
- The screen memory consists of 8,192 words, starting at base address 16,384 and ending at
   address 24,575 (inclusive)
- The 16 bits of a word are counted from 0 to 15, therefore bit_0 to bit_15 of a word in the video RAM
  represent 16 pixels.
 
There is no bit 0 in a RAM register.
  I'm not sure what you mean by that? Each RAM register on the Hack platform contains 16 bits.
- The video RAM is organized in a way that 16 consecutive horizontal pixels are represented by one word
- There are 512/16=32 words per row
- There are 256 rows
- To calculate the address inside the video RAM, you need to
   1. consider in which row you are, since every row consists of 32 words: -> row x 32 (usually y*32)
   2. consider in which word inside the row you are, since every word contains 16 horizontal pixels:
       -> col / 16 (usually x/16)
       With x going from 0 to 511 the result is a value from 0 to 31, which tells you in which
       of the 32 words per row you are (see above)
   3. consider the base address -> +16384 (reserved word in the Assembler: SCREEN)
   4. Add all together: address=16384 + (y * 32) + (x/16)
                                // Jack requires the brackets for the right precedence
   - To calculate the bit position inside the word, you take the remainder of 16
      -> col % 16 (usually x%16)
      This will result in a value from 0 to 15, corresponding to bit_0 to bit_15 of the respective word.
Reply | Threaded
Open this post in threaded view
|

Re: Confusion About Column Indexing and Bit Selection in Display Unit Graphic (Module 4.5)

WBahn
Administrator
In reply to this post by BigBang
BigBang wrote
I have a little confusion. In the video course (Module 4.5), a graphic of the display unit is shown (at minute 5:15). This map starts counting from column 0 - 511.

The calculation "col % 16" is used to determine the bit.

If I want to select the first pixel in a row (column 0) and enter a 0 for col in the calculation "col % 16", the result tells me that I should select the 0th bit. There is no bit 0 in a RAM register.

But there is a word 0 and a row 0.

For example, the first pixel in the top left corner cannot be selected with row 0 and col 0. Instead, row 0 and col 1 must be selected.

Example A (row = 0, col = 0)
word: 0 x 32 + 0 / 16 = 0
bit: 0 % 16 = 0

Example B (row = 0, col = 1)
word: 0 x 32 + 1 / 16 = 0
bit: 1 % 16 = 1

So that the calculation "row x 32 + col / 16" works, there are rows 0 - 255.

But the columns in the calculation "row x 32 + col / 16" and "col % 16" are given from 1-512? Is that correct?
Each word in RAM consists of 16 bits, and therefore can be used to store the state of 16 pixels in the screen, such each pixel can only have one of two values.

The screen is 512 columns by 256 rows, for a total of 131,072 pixels. With 16 pixels per word, that means that we can store the state of every pixel in the screen using 8,192 words of RAM (which is 8K words). The Hack platform maps an 8K block of RAM, starting at address 16,384, to the screen. The first word is mapped to the first 16 pixels, the second word to the next 16, and so on. The first 32 words in the screen RAM is used to encode the first row (since 32 words * 16 pixels/word = 256 pixels), the next 32 words are the next row, and so on.

In selecting a particular pixel in RAM, given its row (0-255) and column (0-511), we need to first identify the address of which word in RAM it is stored in. Then, once we know the address in RAM, we need to identify which of the 16 bits within that RAM location is the one for the specific pixel we are interested in.

There are several ways to come at the math, so let's try the following:

Let's number (index) the pixels 0 through 131,071 (i.e., let's forget about RAM and how many pixels are in a RAM cell for the moment), with the top left being pixel 0, the one to the right of it being pixel 1, and so on across the top row. That makes the last pixel on that row pixel 511 and the first pixel on the second row pixel 512. We keep associating pixel locations with pixel indices this way until the bottom-right pixel is assigned index 131,071.


If I number the rows 0-255 and the cols 0-511, then I can calculate the pixel index (P) from the row (R) and column (C) values as

P = 512 * R + C

The value of R tells me how many complete rows of 512 pixels lie above row R, while the value of C tells me how many pixels lie to the left of column C on the row R.

Notice that this only works if we number things starting with 0. That's everything, R, C, and P all start counting from 0.

Now, once I know the index of P, I can easily put the pixels into groups of B pixels each and number the groups starting with 0.

Let's take an aside and imagine that I have a bunch of parts that are serialized, starting with serial number 0, and I put 20 of them in a box, with S/N 0 on the left and S/N 19 on the right. I number this box Box 0 and put it on a shelf. I put the next 20 items in Box 1, and so on.

Sometime later, someone comes along and want the item with S/N 4271. Which box is it in? If I divide 4271 by 20, I get 213.55. This tells me that there are 213 full boxes before the one that contains the one I want and that the one I want is in the 214th box. But because I numbered the boxes starting with 0, the number written on it is actually 213. So I can find the box number just by dividing the serial number by 20 and throwing away any fractional part.

But what about the part's position within Box 213?

Well, I can get that by going back to the first kind of division I learned, back before I knew about decimal points or even fractions. Back then, if asked to divide 4271 by 20, I would have written the answer as

4271 / 20 = 213 r 11

The integer quotient is the box number, and the remainder is the position within the box (assuming that we start counting with 0 as the first box and the first position within a box).

In the Hack (and most programming languages), when you divide one integer by another, the quotient that is returned is the integer quotient, which is exactly what we want. We also have the remainder operator, %, which returns the remainder after integer division, which again is exactly what we want. So

box = (serial_number) / (items_per_box)
position = (serial_number) % (items_per_box)

We can use this same approach to put out pixels into groups of 16 pixels in a RAM word.

ram_offset = P / 16
bit_offset = P % 16

The ram_offset is how may RAM cells the desired cell is beyond the beginning of the screen memory. So if ram_offset turns out to be 0, that means that the RAM address we want is SCREEN (i.e., 16,384).

ram_address = SCREEN + P/16

Now we just need to replace P with the expression for it in terms of R and C and then simplify.

ram_address = SCREEN + ((512*R + C) / 16)
bit_offset = (512*R + C) % 16

ram_address = SCREEN + (512*R/16) + (C/16)
ram_address = SCREEN + (32*R) + (C/16)

bit_offset = (512*R)%16 + C%16
bit_offset = C % 16

The simplification of the bit_offset comes about because 512 is evenly divisible by 16, and therefore so is any integer multiple of it. Hence, when we divide 512*R by 16, we are guaranteed to get a remainder of zero, regardless of what R happens to be.

Now, within a RAM location, we need to number the sixteen bits 0 through 15 (since we need to start ALL counting at zero for the math to work), but we are free to do that in any way we want. The designers of the Hack I/O mapping chose to associate the least-significant bit with the left-most pixel (of that group of sixteen) and the most-significant bit with the right-most pixel. That may seem counter-intuitive since we normally write the least-significant digit of a number on the right, but it actually makes the instruction sequence needed to access the desired bit, particular in the limited Hack assembly language, a LOT simpler.
Reply | Threaded
Open this post in threaded view
|

Re: Confusion About Column Indexing and Bit Selection in Display Unit Graphic (Module 4.5)

BigBang
Thank you for your explanations. Now I get it!

My fault. Of course 0-15 are 16 possibilities, so 16 bits. Now it makes sense.

And the result of col % 16 gives an integer between 0-15. 0 is simply the first bit of the word and 15 is the 16th bit.