Modern CPU – Protected Mode

The Modern CPU allows the system to protect the memory from violated access. Which means that the system may be able limit the memory that a program can access.

Protected mode is an operational mode of the Intel 80286-compatible CPU. Operation mode of CPU decided how CPU uses registers, seeks memory address and does other works.

Usually, the CPU enables the protected mode once the operation system is booted. Once the CPU enters protected mode, the OS is able to perform modern features like multi-tasking, paging, virtual memory, etc. Also, protected mode enables the OS obtaining the fully control of the program, which means that OS can monitor what the program does, how to perform tasks, how much memory the program allocated etc. Even if the program caused memory leak, the system is still able to free the memory via killing the program that caused memory leak.

Also, the program may not able to directly access the memory that not allocated for the program. For example, the program cannot access the memory address that storing the system binaries, or another program memory area.

However, to finish necessary tasks, the OS still offers some opportunities to allow the program to access some sensitive information of the system or other applications.

That is system call.

Lab 1

Open Source

Open Source means that the source code of a software is public visible. Usually, Open Source code can be used for free with some limitation, e.g. the software used open source code should be a open source software, there are limitation of re-development based on the open source code, or the code cannot be used for business purpose for free, and so on.

Most of Open Source projects are under a specific open source license.

In this blog, I will choose Drupal and Linux Kernel as example to show how open source community works.

Drupal

Drupal is an open source content management system(CMS) framework that is written in PHP and it is distributed user the GNU General Public License. Drupal is developed by Drupal community and is free.

In Drupal community, all issues will be reported to https://www.drupal.org/project/issues

Before reporting an issue, the user should create an account and login to drupal.org. After user logged in, the Drupal website will allow user to fill a form and submit the form to drupal.org. Then drupal community will review the issue and assign a status to the issue in the issue page. Depends on different situation, Drupal team may fix the issue or not.

Linux Kernel

Linux kernel is a free and open source operating system kernel. The code in Linux Kernel are under different licenses, e.g. GPL, BSD, MIT, etc.

Linux kernel issues will be listed and reported on https://bugzilla.kernel.org/ . If user wants to report an issue, user must create an account or login to continue. After an issue is reported, the issue will be assigned status of NEW. After Linus and the people in the team tested and verified the bug, they will assign the issue other status like VERIFIED, FIXED, REJECTED, etc.

Both of Linux kernel and Drupal allow public user to report bugs and their team will try to verify and fix the bugs. The advantage is the billion of people on the planet help them to test their software and report bugs on time.

However, there are also some drawbacks for this approach. The team cannot make sure that the “bug” is not caused by user’s skill level. The user may does not have skill to fix an error and they report it as “bug”. In this case, the community needs lots of time to verify and answer user’s questions.

However, open source is the trends of programming. Open Source communities contributed countless valuable projects and software. Also, it helps programmers on the world to improve their coding skills.

Issue observed:

https://bugzilla.kernel.org/show_bug.cgi?id=203805

https://bugzilla.kernel.org/show_bug.cgi?id=204873

https://www.drupal.org/project/backfill_formatter/issues/3110229

https://www.drupal.org/project/cloud/issues/3108485

Websites:

https://bugzilla.kernel.org/

https://www.drupal.org/

https://www.kernel.org/

Lab 3

 define WIDTH 	5 ; width of graphic
 define HEIGHT 	5 ; height of graphic

 	lda #$00	; create a pointer at $10
 	sta $10		;   which points to where
 	lda #$02	;   the graphic should be drawn
 	sta $11
  
 	lda #$00	; number of rows we've drawn
 	sta $12		;   is stored in $12
 
 	ldx #$00	; index for data
 	ldy #$00	; index for screen column

move: 
	jsr clearScreen
	;brk
	jsr moveDown
	jsr moveRight
	;draw will modify our pointer, we need to backup and reset it later
	lda $10
	sta $14;backup
	lda $11
	sta $15 
	jsr draw
	lda $14
	sta $10;reset
	lda $15
	sta $11
	;brk
	jsr move 
 
 draw:	
	lda data,x
 	sta ($10),y 
 	inx
 	iny 
 	cpy #WIDTH 
	;brk
 	bne draw
   
 	inc $12		; increment row counter
 
 	lda #HEIGHT	; are we done yet?
 	cmp $12
 	bne continue	; if not equal, go to continue
	;beq done;	; comment out bne continue and beq done > movin

	;lda $04;
	;sta $11
	ldx #$00; //reset index
	ldy #$00;
	sty $12
	rts
  
continue: 	 
	;brk;
	lda $10		; load pointer
 	clc 
 	adc #$20	; add 32 to drop one row
 	sta $10
 	lda $11	; carry to high byte if needed
 	adc #$00
	cmp #$06
	beq done
 	sta $11 
 
 	ldy #$00
 	beq draw
	;rts
  
 done:	brk		; stop when finished
	;rts
 
 data:
 dcb 00,03,03,03,00
 dcb 07,00,00,00,07
 dcb 07,00,00,00,07
 dcb 07,00,00,00,07
 dcb 00,03,03,03,00

moveRight: 	
	sty $13
	ldy $10
	iny	
	sty $10
	ldy $13
	rts

moveDown: 
	lda $10
	clc
	adc #$20 ;add a line
	sta $10
	lda $11
	adc #$00
	cmp #$06
	beq done
	sta $11
	rts

resetPage:
	lda #$02
	sta $11
	rts

clearScreen: ;we can create another sub route called clearPrevious to avoid flashing screen
	sta $22 ;backup registers
	stx $23
	sty $24	

	lda #$00	;   create a pointer at $80
 	sta $20		;   which points to where
 	lda #$02	;   the graphic should be drawn
 	sta $21
	lda #$00 ;black color
	ldy #$00 ;
mloop:
	sta ($20), y
	iny
	bne mloop
	
	ldx $21
	inx
	stx $21
	cpx #$06
	bne mloop

	lda $22 ;revert registers
	ldx $23
	ldy $24
	rts

The code above is what I’ve done so far.

In Lab 3 our group will create a shape that will bounce around that will reflect when it reaches screen edge.

So far, the shape is able to move from top left to bottom right. But when the it is drawing the picture at bottom right, it will write data to 0x0600, where our program located. Then the program crushed.

Procedure:

When the program starts, we load the image from dcb data. and draw it at the address where our pointer point at. Then we modify the pointer, clear screen, then draw it again.

move: 
	jsr clearScreen
	;brk
	jsr moveDown
	jsr moveRight
	;draw will modify our pointer, we need to backup and reset it later
	lda $10
	sta $14;backup
	lda $11
	sta $15 
	jsr draw
	lda $14
	sta $10;reset
	lda $15
	sta $11
	;brk
	jsr move 

However, draw modifies our pointer to complete drawing, therefore, we backed it up and restored it after drawing finished. After restoring pointer, we come back to move sub route, and clear screen again, then modify our pointer and draw it again.

clearScreen: ;we can create another sub route called clearPrevious to avoid flashing screen
	sta $22 ;backup registers
	stx $23
	sty $24	

	lda #$00	;   create a pointer at $80
 	sta $20		;   which points to where
 	lda #$02	;   the graphic should be drawn
 	sta $21
	lda #$00 ;black color
	ldy #$00 ;
mloop:
	sta ($20), y
	iny
	bne mloop
	
	ldx $21
	inx
	stx $21
	cpx #$06
	bne mloop

	lda $22 ;revert registers
	ldx $23
	ldy $24
	rts

Clear screen is simple. we fill 00 from address 0x0200 until 0x05FF. But it is very slow. This is planned to be optimized. Because we know where we drew, so we just need to erase that addresses.

moveRight: 	
	sty $13
	ldy $10
	iny	
	sty $10
	ldy $13
	rts

moveDown: 
	lda $10
	clc
	adc #$20 ;add a line
	sta $10
	lda $11
	adc #$00
	cmp #$06
	beq done
	sta $11
	rts

moveRight and moveDown is also simple.

In moveRight, we just increased pointer index by 1, so it moves right 1 pixel. But the shape does not reflect after it reaches right edge. We need to check if it reaches right edge and change the increase so decrease if it reaches right edge.

In moveDown, we increase pointer index by 32(hex 20). if there is a borrow, it means we need to switch page(e.g. from 0x0200 to 0x0300), so we add 0. if there is a borrow, it will add 1 instead of 0.

We will finish this lab next week. We plan to create an X and Y coordinator function to manage where our shape is, so we can easily to deal with the reflection issue.

To be continued!

6502 Terms

To under 6502 assembly language, the terms are necessary to understand.

Address

Address is the numeric reference to a specific memory location. 6502 is a 8-bit cpu, therefore, every memory location contains 8 bits. Address is recorded as hex number. it starts from 0x0000 to 0xFFFF in 6502. So we can calculate that the memory size of 6502 is 64KB.

Addressing Mode

Addressing Mode is a method used to find the data(operands) for an instruction. In 6502, we need 16 bit to save a pointer. So when accessing a pointer, e.g. 0x1234 saved at 0x0010 and 0x0011, when we access the pointer, we need to access 0x0010 – lda $10. The operand of this operation looks like indirect, but it actually is zero-page. The reason the data is saved in 00 page(0x00??). For the statement that does not have an operand but it is dealing with data, usually the operands of those statements are Accumulator – Register A. For example: asl

Assembly Language

Assembly Language is a language that can directly control machine but still human readable. Assembly language will directly translated to machine code with out any other process.

Bitwise Operation

Usually, bitwise operation means shifting right and left. Shifting left means multiple the number in register by 2, shift right usually means divide the number in register by 2. Bitwise does not do any logic operation, so it is very fast. Also, if we need to access a 1-bit data, we need to use bitwise operation. For example: we want to know what is the first bit at 0x1000, we need to get the 8 bits data, and shift right 7 times. in this case, we get the first bit at 0x1000

Register

Register is a fast internal storage location for data with in a CPU. In 6502, we use 3 registers: A, X, Y. A is accumulator, x and y are general registers. CPU can directly control registers. When need to process data in memory, CPU takes the data from the memory to register, then put it back. Register is much faster than memory, so it using registers effectively is very important for optimizing software.

Stack

Stack is a region of memory used for first-in, last-out data storage. The stack is in memory, not inside of the CPU. In 6502, the stack located at 01 page. Stacks start from high address, therefore, the stack from 0x0100 to 0x01FF

Program Counter

Program Counter is a pointer to currently-executing code. When a operation executed, the program counter increases. Therefore, it always points at next statements. When program counter points at address which the content in the address is 00, program ends.

Status Register

Status Register is a collection of status and mode flags. CPU needs to save some status, for example, there is a overflow after an add operation, in this case, we need a place to store status like this. In 6502, it is (bit 7)NV-BDIZC(bit 0). It represents

N: Negative flag, set true if the result of an operation is negative.

V: Overflow flag, when an arithmetic operation resulted in a result of greater than FF or less than 00, V set

-: Not Used

B: this is set when encountered interrupt.

D: This is decimal mode status flag. Use binary coded decimal to do add or subtract operation

I: This is Interrupt enable or disable flag. Disable not available if it is set

Z: Zero flag. This is set when a operation resulted in 0; cleared when a operation resulted a non-zero value.

C: Carry flag. This is set when borrow is required; cleared when borrow is not required. most used flag in 6502 processor.

Disassembly

Translate machine language to human readable language – assembly language.

Word Size

Word Size is a description of the allocation of storage within memory

Lab 2 – 6502 Assembly Language(Not finished yet)

In Lab 2, We learned Assembly language base on 6502.

Here is the code:

lda #$00	; set a pointer at $40 to point to $0200
	sta $40
	lda #$02
	sta $41

	lda #$07	; colour

	ldy #$00	; set index to 0

loop:	sta ($40),y	; set pixel

	iny		; increment index
	bne loop	; continue until done the page

	inc $41		; increment the page
	ldx $41		; get the page
	cpx #$06	; compare with 6
	bne loop	; continue until done all pages


After we run the code above on 6502 Emulator, the screen will be filled by yellow.

Now we add tya between “loop” and “sta ($40), y” the screen will be filled by different color lines. The reason why it happens is that we write the data in register A to the screen pixels. Before we add tya, the data in a is #$07(yellow). But after we added tya, the data in register A will be changed in every loop from 00 to ff, the screen only take the last digit of the hex code as color code, so it only shows 16 color(0 – f). The screen size is 32*32(1024 pixels) and the screen contains 4 pages, from 0x200 until 0x50FF. so every page contains 256 (16*16) pixels and controls 8 (256 = 8*32) horizontal lines on the screen. Therefore, 16 colors pixels circle(0 – f) shows twice in a line cause a line has 32 pixels.

Now, let’s add lsr after tya. lsr shifts bit right for the data in register A, where saving the data that will be write to the screen. What gonna happen?

Well, it divides the unsigned integer stored in register A(we shift right once so that the integer is divided by 2^1). In this case, after we go through a line, the 16 colors circle only shows once and every color is showed twice.

Output when we shift bit right once

What if we add lsr once again?

We can predict that the color code will be divided by 4(2^2). In this case, we need 64 (loop 64 times, 16 = 64/4) pixels to show a 16 color circle and every color will be shown 4 times. We believe the vertical line will be break cause the number for pixels in each line cannot be divided by loop times of a circle of showing all colors.

shift right twice, lines break

What if we delete all lsr and write an asl between loop and sta ($40), y?

In this case, we can make sure that the last digit of data in register A will not be an odd number because the data in register A is multiple by 2.

we can see the last digit will be 0, 2, 4, 6, 8 ,A, C, E, 0…

There are only 8 colors in a color circle!

Also when we shift again, the number of colors reduces by half. Until there will only be 0 at the last of the color data, the screen will only show black


result of shift left 3 times, only 2 colors left.

Now we play around with register A, what if you do something to register Y, what will be the result?

Let’s clear all tya and asls, and add an extra iny.

In this case, our program will not go through the whole screen, it will actually go through half of the screen because the y will never be an odd number before it reach 00 – end of the loop. So, if there are 4 iny, the program will only render one fourth of the screen.

result of we having 4 inys

What if we have 3 inys?

This will be an interesting questions. For 3 inys, the program will render 0, 3, 6, 9, C, F for the first circle. What’s next? the data got overflow, so F+3 will be 2!

Then its rendering, 2, 5, 8, B, E then overflow again, E+3 is 1 and start loop again: 1, 4, 7, A, D. After we add 3 again, the data will be 0, loop end. so that can say that if we increase y odd times, it will finally render the whole screen – just slower!

write 1

Writes 1 – lines on the top and bottom:

;write 1 line on top and bottom.	
    
    
    lda #$00	; set a pointer at $40 to point to $0200
	sta $40	; I still don't know why it is pointed to $0200, needing answer
	lda #$02
	sta $41

	lda #$05	; colour

	ldy #$00	; set index to 0

loop:	
	sta ($40),y	; set pixel
	iny		; increment index
	cpy #$20	; compare index, 20 - end of first line
	bne loop	; continue until done the page
	lda #$00	; fill black to other pixels
	inc $41		; increment the page
	ldx $41		; get the page
	cpx #$05	; if last page of the screen - last 1/4
	bne loop

loop2:
	;sta ($40),y ; this line is not needed
	iny ; increase index
	cpy #$E0 ; compare index, E0, last line of the page
	bne loop2
	lda #$05 ; set green color
loop3: 
	sta ($40),y ; set pixels
	iny
	bne loop3

In this approach, we render the first line of screen: 0x0200 – 0x022F, first 32 pixels in first page.

Then we will ignore all other pixels of the page until we got 0x05E0, the last line of the screen, last 32 pixels in last page. then we render it, we got lines on the top and bottom

Write 2 – lines on the left and right:

; write 2 line left and right

	lda #$00	; set a pointer at $40 to point to $0200
	sta $40
	lda #$02
	sta $41
	lda #$00
	sta $42 ;counter to 0

	lda #$07	; colour yellow
	ldy #$00	; set index to 0
	sta ($40),y
loop:	
	iny		; increment index
	inc $42; ; increment counter
	ldx $42; load the counter
	cpx #$1F;  check if the counter 1F(32) - it is the last pixel of the line.
	bne loop; if no, loop until get the last pixel of the line. 
	lda #$04; color purple
	sta ($40), y ;set pixels
	iny ;increment index
	lda #$07; 
	sta ($40), y ;we got the first pixel of next line, or the first pixel of the page.
	ldx #$00; reset counter
	stx $42; store the counter back
	cpy #$00; 
	bne loop;loop until done of the page.

	inc $41		; increment the page
	ldx $41		; get the page
	cpx #$06	; compare with 6
	bne loop	; continue until done all pages
write 2 result

If we want to render the line on the left and right, we can render the first pixel and the last pixel of every line. We know that every line has 32 pixels, so we need a counter to know if we are in the the last pixel of a line – next pixel must be the first pixel of next line!

But there is an issue, when the program reach the last of a page, it cannot get the first pixel of next page because the address is pointed by the pointer! However, our program still rendered 2 lines as expected. Why?

After we reached the last pixel of a page, we need try to get the first pixel of next line and the machine does give our program a pixel – but it is the first pixel of current page instead of the first pixel of next line!

My impression of the Assembly Language:

It scared me when I first time heard about it. But actually when I am doing it, it is not hard as I thought. It is actually let the programmer program a machine step by step in a lower level. We have more control of memory so that we can write a high performance program.

I played a game call Human Resources Machine, which is very similar with writing in Assembly Language.

The loop, if, switch statements in higher level language like C/C++ are actually implemented by Jump function in Assembly!

(To be continued)

Shichao’s SPO600 Course Blog

This Blog is used for SPO600 at Seneca College. As required, I will maintain this blog, at least, until the end of April 2020.

My Name is Shichao Wang, a CPA student at Seneca College. I enjoy program using C/C++, C#, Java, JavaScript.

Why did I take this course?

  • Learn some assembly to improve my code performance
  • Know how open source communities work
  • Lean more low-level coding logic to understanding computer.

Design a site like this with WordPress.com
Get started