├── AssmSoft.zip ├── README ├── c01-01.asm ├── c02-01.asm ├── c02-02.asm ├── c02-03.asm ├── c02-04.asm ├── c02-05.asm ├── c02-06.asm ├── c02-06b.asm ├── c02-07.asm ├── c02-07b.asm ├── c02-08.asm ├── c02-09.asm ├── c02-10.asm ├── c03-01.asm ├── c03-01b.asm ├── c04-01.asm ├── c04-02.asm ├── c04-03.asm ├── c05-01.asm ├── c06-01.asm ├── c06-02.asm ├── c06-03.asm ├── c06-04.asm ├── c06-05.asm ├── c07-01.asm ├── c07-02.asm ├── c07-03.asm ├── c07-04.asm ├── c08-01.asm ├── c08-02.asm ├── c09-01.asm ├── c09-01.c ├── c10-01.sh ├── r01-01.S.s └── r01-02.S.s /AssmSoft.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/recluze/assembly-lang-course/2e97c17ee256d35604359f62848d77514e0c76a2/AssmSoft.zip -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | # Resources for course: Computer Organization and Assembly Language 2 | # recluze.net 3 | 4 | # See full video course (in Urdu language) here: https://www.youtube.com/watch?v=eobVpYqvMGE&list=PLnd7R4Mcw3rJCvAduQxyySvejtBIaPs0O 5 | 6 | # To set up in Ubuntu 20.04+ 7 | 8 | 9 | # Install Doxbox 10 | sudo apt install dosbox 11 | dosbox 12 | 13 | # Inside dosbox (give it some path in your host machine) 14 | # Put extracted contents of the zip file and .asm files in this folder on your host machine 15 | 16 | mount c /home/nam/ee213 17 | 18 | c: 19 | 20 | # Assemble and run 21 | nasm c.asm -o c.com 22 | afd c.com 23 | 24 | # Assemble with Listing 25 | nasm c.asm -l c.lst -o c.com 26 | 27 | # If after changing files, they do not show up in dosbox, hit Ctrl+F4 inside the dosbox window. 28 | 29 | 30 | Zip file contains the 16-bit NASM and "Advanced Fullscreen Debugger". 31 | -------------------------------------------------------------------------------- /c01-01.asm: -------------------------------------------------------------------------------- 1 | [org 0x0100] 2 | 3 | ; start of code 4 | 5 | mov ax, 5 ; move the constant 5 into register ax 6 | mov bx, 10 7 | 8 | add ax, bx ; add value of bx into the value of ax 9 | 10 | mov bx, 15 ; add constant 15 into the value of bx 11 | add ax, bx 12 | 13 | mov ax, 0x4c00 ; exit .. 14 | int 0x21 ; .. is what the OS should do for me 15 | 16 | 17 | 18 | 19 | 20 | ; watch the listing carefully -------------------------------------------------------------------------------- /c02-01.asm: -------------------------------------------------------------------------------- 1 | ; a program to add three numbers using memory variables 2 | [org 0x0100] 3 | 4 | mov ax, [num1] ; load first number in ax 5 | ; mov [num1], [num2] ; illegal 6 | mov bx, [num2] 7 | add ax, bx 8 | mov bx, [num3] 9 | add ax, bx 10 | mov [num4], ax 11 | mov ax, 0x4c00 12 | int 0x21 13 | 14 | 15 | num1: dw 5 16 | num2: dw 10 17 | num3: dw 15 18 | num4: dw 0 19 | 20 | 21 | ; watch the listing carefully -------------------------------------------------------------------------------- /c02-02.asm: -------------------------------------------------------------------------------- 1 | ; a program to add three numbers accessed using a single label 2 | [org 0x0100] 3 | 4 | mov ax, [num1] 5 | mov bx, [num1 + 2] ; notice how we can do arithmetic here 6 | add ax, bx ; also, why +2 and not +1? 7 | mov bx, [num1 + 4] 8 | add ax, bx 9 | mov [num1 + 6], ax ; store sum at num1+6 10 | mov ax, 0x4c00 11 | int 0x21 12 | 13 | num1: dw 5 14 | dw 10 15 | dw 15 16 | dw 0 -------------------------------------------------------------------------------- /c02-03.asm: -------------------------------------------------------------------------------- 1 | ; a program to add three numbers accessed using a single label 2 | [org 0x0100] 3 | 4 | mov ax, [num1] 5 | mov bx, [num1 + 2] 6 | add ax, bx 7 | mov bx, [num1 + 4] 8 | add ax, bx 9 | mov [num1 + 6], ax 10 | mov ax, 0x4c00 11 | int 0x21 12 | 13 | num1: dw 5, 10, 15, 0 14 | -------------------------------------------------------------------------------- /c02-04.asm: -------------------------------------------------------------------------------- 1 | ; a program to add three numbers directly in memory 2 | [org 0x0100] 3 | 4 | mov ax, [num1] 5 | mov [num1 + 6], ax ; add this value to result 6 | 7 | mov ax, [num1 + 2] 8 | add [num1 + 6], ax 9 | 10 | mov ax, [num1 + 4] 11 | add [num1+6], ax 12 | 13 | mov ax, 0x4c00 14 | int 0x21 15 | 16 | 17 | num1: dw 5, 10, 15, 0 18 | 19 | 20 | ; should have the result separate! 21 | ; let's change that! 22 | -------------------------------------------------------------------------------- /c02-05.asm: -------------------------------------------------------------------------------- 1 | ; a program to add three numbers using byte variables 2 | [org 0x0100] 3 | 4 | mov ax, [num1] 5 | 6 | mov bx, [num1+1] 7 | add ax, bx 8 | 9 | mov bx, [num1+2] 10 | add ax, bx 11 | 12 | mov [num1+3], ax 13 | 14 | mov ax, 0x4c00 15 | int 0x21 16 | 17 | num1: db 5, 10, 15, 0 18 | 19 | ; something's wrong with this code. 20 | ; let's figure out what that is! -------------------------------------------------------------------------------- /c02-06.asm: -------------------------------------------------------------------------------- 1 | ; a program to add three numbers using byte variables 2 | [org 0x0100] 3 | ; mov ax, 0x8787 4 | ; xor ax, ax ; We need to make sure AX is empty! Or do we? 5 | 6 | mov ah, [num1] ; Intel Sotware Developer Manual - Figure 3-5 (Page 76) 7 | 8 | mov bl, [num1+1] 9 | add ah, bh 10 | 11 | mov bh, [num1+2] 12 | add ah, bh 13 | 14 | mov [num1+3], ah 15 | 16 | mov ax, 0x4c00 17 | int 0x21 18 | 19 | num1: db 5, 10, 15, 0 20 | -------------------------------------------------------------------------------- /c02-06b.asm: -------------------------------------------------------------------------------- 1 | ; a program to add three numbers using byte variables 2 | [org 0x0100] 3 | 4 | mov ax, 0x8787 5 | xor ax, ax ; we need to make sure AX is empty! 6 | 7 | mov al, [num1] 8 | 9 | mov bl, [num1+1] 10 | add al, bl 11 | 12 | mov bl, [num1+2] 13 | add al, bl 14 | 15 | mov [num1+3], al 16 | 17 | 18 | 19 | ; mov ax, bl ; ... assemble time error. Make sure you understand the error! 20 | 21 | mov ax, 0x4c00 22 | int 0x21 23 | 24 | num1: db 5, 10, 15, 0 25 | -------------------------------------------------------------------------------- /c02-07.asm: -------------------------------------------------------------------------------- 1 | ; a program to add three numbers using byte variables 2 | [org 0x0100] 3 | xor ax, ax ; check effect on ZF 4 | 5 | mov bx, num1 6 | 7 | add ax, [bx] 8 | add bx, 2 9 | 10 | add ax, [bx] 11 | add bx, 2 12 | 13 | add ax, [bx] 14 | add bx, 2 15 | 16 | 17 | mov [result], ax 18 | 19 | mov ax, 0x4c00 20 | int 0x21 21 | 22 | 23 | ; to turn this into an iteration, we need a couple of things: 24 | ; - branching instruction 25 | ; - checking constraints -- e.g. c > 0 ; Intel Sotware Developer Manual - Figure 3-8 (Page 80) 26 | 27 | 28 | num1: dw 5, 10, 15 29 | result: dw 0 30 | -------------------------------------------------------------------------------- /c02-07b.asm: -------------------------------------------------------------------------------- 1 | ; a program to add three numbers using byte variables 2 | [org 0x0100] 3 | 4 | ; for (int c = 3 c > 0 c--) { 5 | ; result += data[c]; 6 | ;} 7 | 8 | 9 | 10 | ; initialize stuff 11 | mov ax, 0 ; reset the accumulator 12 | mov cx, 3 ; set the iterator count 13 | mov bx, num1 ; set the base 14 | 15 | outerloop: 16 | add ax, [bx] 17 | add bx, 2 18 | 19 | sub cx, 1 20 | jnz outerloop 21 | 22 | 23 | mov [result], ax 24 | 25 | mov ax, 0x4c00 26 | int 0x21 27 | 28 | 29 | ; Intel Sotware Developer Manual - EFLAGS and Instructions (Page 435) 30 | 31 | num1: dw 5, 10, 15 32 | result: dw 0 33 | -------------------------------------------------------------------------------- /c02-08.asm: -------------------------------------------------------------------------------- 1 | ; a program to add three numbers using byte variables 2 | [org 0x0100] 3 | 4 | ; initialize stuff 5 | mov ax, 0 ; reset the accumulator 6 | mov cx, 10 ; set the iterator count 7 | mov bx, 0 ; set the base 8 | 9 | outerloop: 10 | add ax, [num1 + bx] 11 | add bx, 2 12 | 13 | sub cx, 1 14 | jnz outerloop 15 | 16 | 17 | mov [result], ax 18 | 19 | mov ax, 0x4c00 20 | int 0x21 21 | 22 | 23 | ; Intel Sotware Developer Manual - EFLAGS and Instructions (Page 435) 24 | 25 | num1: dw 10, 20, 30, 40, 50, 10, 20, 30, 40, 50 26 | result: dw 0 27 | -------------------------------------------------------------------------------- /c02-09.asm: -------------------------------------------------------------------------------- 1 | ; a program to add three numbers using byte variables 2 | [org 0x0100] 3 | 4 | ; initialize stuff 5 | mov ax, 0 ; reset the accumulator 6 | mov bx, 0 ; set the counter 7 | 8 | outerloop: 9 | add ax, [num1 + bx] 10 | add bx, 2 11 | 12 | cmp bx, 20 ; sets ZF=0 when they are equal 13 | jne outerloop 14 | 15 | 16 | mov [result], ax 17 | 18 | mov ax, 0x4c00 19 | int 0x21 20 | 21 | 22 | ; Intel Sotware Developer Manual - EFLAGS and Instructions (Page 435) 23 | 24 | num1: dw 10, 20, 30, 40, 50, 10, 20, 30, 40, 50 25 | result: dw 0 26 | -------------------------------------------------------------------------------- /c02-10.asm: -------------------------------------------------------------------------------- 1 | [org 0x0100] 2 | 3 | jmp start ; see next instructions when you haven't yet executed this! 4 | 5 | num1: dw 10, 20, 30, 40, 50, 10, 20, 30, 40, 50 6 | result: dw 0 7 | 8 | 9 | 10 | start: 11 | ; initialize stuff 12 | mov ax, 0 ; reset the accumulator 13 | mov bx, 0 ; set the counter 14 | 15 | outerloop: 16 | add ax, [num1 + bx] 17 | add bx, 2 18 | 19 | cmp bx, 20 ; sets ZF=0 when they are equal 20 | jne outerloop 21 | 22 | 23 | mov [result], ax 24 | 25 | mov ax, 0x4c00 26 | int 0x21 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /c03-01.asm: -------------------------------------------------------------------------------- 1 | [org 0x0100] 2 | 3 | jmp start 4 | 5 | data: dw 6, 4, 5, 2 6 | 7 | 8 | start: 9 | mov cx, 4 ; make 4 passes, has to be outside the loop! 10 | 11 | outerloop: 12 | mov bx, 0 13 | 14 | innerloop: 15 | mov ax, [data + bx] 16 | cmp ax, [data + bx + 2] ; why did we move the value to AX? 17 | 18 | jbe noswap ; if we don't have to swap, we just jump over the swap thing 19 | ; think of this as the "if" 20 | 21 | ; the swap potion 22 | mov dx, [data + bx + 2] 23 | mov [data + bx + 2], ax ; again with the AX? 24 | mov [data + bx], dx 25 | 26 | noswap: 27 | add bx, 2 28 | cmp bx, 6 29 | jne innerloop 30 | 31 | ; check outer loop termination 32 | sub cx, 1 33 | jnz outerloop 34 | 35 | 36 | ; exit system call 37 | mov ax, 0x4c00 38 | int 0x21 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /c03-01b.asm: -------------------------------------------------------------------------------- 1 | [org 0x0100] 2 | 3 | jmp start 4 | 5 | data: dw 6, 2, 4, 5 6 | swap: db 0 ; use this as a flag 7 | 8 | start: 9 | ; mov cx, 4 ; make 10 passes, has to be outside the loop! 10 | 11 | outerloop: 12 | mov bx, 0 13 | mov byte [swap], 0 ; why the "byte"? 14 | 15 | innerloop: 16 | mov ax, [data + bx] 17 | cmp ax, [data + bx + 2] ; why did we move the value to AX? 18 | 19 | jbe noswap ; if we don't have to swap, we just jump over the swap thing 20 | 21 | ; the swap potion 22 | mov dx, [data + bx + 2] 23 | mov [data + bx + 2], ax ; again with the AX? 24 | mov [data + bx], dx 25 | mov byte [swap], 1 26 | 27 | noswap: 28 | add bx, 2 29 | cmp bx, 6 30 | jne innerloop 31 | 32 | ; if we didn't swap even once, we should be done 33 | cmp byte [swap], 1 ; don't need to load this in register? 34 | je outerloop 35 | 36 | ; check outer loop termination 37 | ; sub cx, 1 38 | ; jnz outerloop 39 | 40 | 41 | ; exit system call 42 | mov ax, 0x4c00 43 | int 0x21 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /c04-01.asm: -------------------------------------------------------------------------------- 1 | [org 0x0100] 2 | 3 | jmp start 4 | 5 | multiplicand: db 13 ; 4-bit number, save space of 8-bits 6 | multiplier: db 5 ; 4-bit 7 | 8 | result: db 0 ; 8-bit result 9 | 10 | start: 11 | 12 | mov cl, 4 ; how many times we need to run the loop 13 | mov bl, [multiplicand] 14 | mov dl, [multiplier] 15 | 16 | 17 | checkbit: 18 | shr dl, 1 ; do the rotation so that right bit is thrown in CF 19 | jnc skip 20 | add [result], bl ; only add if CF IS SET 21 | 22 | 23 | skip: 24 | shl bl, 1 ; always shift the multiplicand 25 | 26 | dec cl 27 | jnz checkbit 28 | 29 | 30 | mov ax, 0x4c00 31 | int 0x21 -------------------------------------------------------------------------------- /c04-02.asm: -------------------------------------------------------------------------------- 1 | [org 0x0100] 2 | 3 | jmp start 4 | 5 | num1: dw 0x40FF ; 4400, 40FF 6 | 7 | dest: dw 0x40FF 8 | src: dw 0x1001 9 | 10 | 11 | start: 12 | 13 | ; shift 14 | shl byte [num1], 1 15 | rcl byte [num1 + 1], 1 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ; addition 24 | xor ax, ax ; clear 25 | 26 | mov al, byte[src] 27 | add byte[dest], al 28 | 29 | mov al, [src + 1] 30 | adc byte[dest + 1], al 31 | 32 | 33 | 34 | mov ax, 0x4c00 35 | int 0x21 36 | 37 | -------------------------------------------------------------------------------- /c04-03.asm: -------------------------------------------------------------------------------- 1 | [org 0x0100] 2 | 3 | jmp start 4 | 5 | multiplicand: dw 0xC8 ; 200 = 0b 11001000 6 | multiplier: db 0x32 ; 50 = 0b 00110010 7 | result: dw 0 ; should be 10,000 = 0x2710 8 | 9 | start: 10 | 11 | mov cl, 8 12 | mov dl, [multiplier] 13 | 14 | 15 | checkbit: 16 | shr dl, 1 17 | jnc skip 18 | 19 | mov al, [multiplicand] ; extended addition 20 | add byte [result], al 21 | mov al, [multiplicand + 1] 22 | adc byte [result + 1], al 23 | 24 | skip: 25 | shl byte [multiplicand], 1 ; extended shift 26 | rcl byte [multiplicand + 1], 1 27 | 28 | 29 | dec cl 30 | jnz checkbit 31 | 32 | 33 | 34 | 35 | ; exit syscall 36 | mov ax, 0x4c00 37 | int 0x21 38 | 39 | 40 | 41 | 42 | 43 | ; helpful bash commands 44 | 45 | ; hex to dec 46 | ; echo $((16# F)) 47 | 48 | ; dec to hex 49 | ; printf '%x\n' 15 50 | 51 | ; bin to hex 52 | ; printf '%x\n' "$((2# 110010))" 53 | 54 | ; hex to bin 55 | ; printf '\x32' | xxd -b | cut -d' ' -f2 56 | -------------------------------------------------------------------------------- /c05-01.asm: -------------------------------------------------------------------------------- 1 | ; Let's run a 32-bit program in Ubuntu! 2 | 3 | ; Install NASM in Ubuntu: 4 | ; sudo apt install nasm 5 | 6 | ; Create this code file 7 | 8 | ; Assemble: 9 | ; nasm -f elf32 -l c05-01.lst -o c05-01.o c05-01.asm 10 | ; 11 | ; We want to create a format that Linux understand 12 | ; i.e. ELF format in 32-bits 13 | ; (we also create a listing file) 14 | ; Read more about ELF here: https://linux-audit.com/elf-binaries-on-linux-understanding-and-analysis/ 15 | 16 | ; Link with shared library that 'understands' the format: ld.so in Linux 17 | ; ld -m elf_i386 -o c05-01 c05-01.o 18 | 19 | ; Run it: 20 | ; ./c05-01 21 | 22 | 23 | 24 | ; Now let's discuss the code! 25 | 26 | ; in modern OSs, programs do not start executing 27 | ; "from the first instruction" 28 | 29 | ; Instead, there is a library (ld.so) that looks for the "start symbol" 30 | ; and executes from there. 31 | 32 | 33 | ; a section "directive" marks the parts of a program 34 | ; for the ELF format (or whatever binary format you are using) 35 | SECTION .text: 36 | 37 | ; We mark the start for this library using the following: 38 | GLOBAL _start 39 | 40 | _start: 41 | ; write the string to console 42 | mov eax, 0x4 ; write syscall is 0x4 43 | mov ebx, 1 ; param - std output should be used 44 | mov ecx, message ; the string to write 45 | mov edx, message_length ; the length of the string 46 | int 0x80 ; invoke the system call 47 | 48 | 49 | ; exit the program 50 | mov eax, 0x1 ; exit system call is 0x1 51 | mov ebx, 0 ; exit code is 0 (return 0) 52 | int 0x80 ; Comment out and see! 53 | 54 | ; note that int is NOT the right way to do things! 55 | ; (more on this later) 56 | 57 | 58 | ; data section here. We can also move it above .code 59 | SECTION .data: 60 | ; 0xA is new line, 0x0 is null terminator 61 | message: db "Hello!", 0xA, 0x0 62 | message_length: equ $-message 63 | 64 | ; message_length: equ 8 65 | ; .... is exactly the same as 66 | ; #define message_length 8 67 | 68 | 69 | 70 | ; Some useful ELF details 71 | ; readelf -a c05-01.o ; shows everything 72 | 73 | ; readelf -h c05-01.o ; shows headers 74 | ; readelf -S c05-01.o ; shows sections 75 | 76 | ; readelf -x 2 c05-01.o ; shows section number 2 77 | ; readelf -x 2 c05-01 ; see the difference between above and this 78 | 79 | 80 | 81 | 82 | 83 | ; View program in GDB 84 | 85 | ; gdb ./c05-01 86 | ; layout regs ; shows registers and disassembled code 87 | ; starti ; start the program interactively 88 | ; si ; execute one machine instruction 89 | ; quit ; exit GDB 90 | 91 | -------------------------------------------------------------------------------- /c06-01.asm: -------------------------------------------------------------------------------- 1 | [org 0x100] 2 | 3 | jmp start 4 | 5 | data: dw 60, 55, 45, 50 6 | swap: db 0 7 | 8 | 9 | bubblesort: 10 | dec cx 11 | shl cx, 1 ; we will be jumping by 2 every time. So, *2 12 | 13 | mainloop: 14 | mov si, 0 ; use as array index 15 | mov byte[swap], 0 ; reset swap flag for this iteration 16 | 17 | innerloop: 18 | mov ax, [bx + si] 19 | cmp ax, [bx + si + 2] 20 | jbe noswap 21 | 22 | mov dx, [bx + si + 2] 23 | mov [bx + si], dx 24 | mov [bx + si + 2], ax 25 | mov byte[swap], 1 26 | 27 | noswap: 28 | add si, 2 29 | cmp si, cx 30 | jne innerloop 31 | 32 | cmp byte[swap], 1 33 | je mainloop 34 | 35 | ret ; notice this!! 36 | 37 | 38 | 39 | 40 | start: 41 | mov bx, data 42 | mov cx, 4 43 | 44 | ; make a function call 45 | call bubblesort 46 | 47 | ; data is now sorted! 48 | 49 | mov ax, 0x4c00 50 | int 0x21 -------------------------------------------------------------------------------- /c06-02.asm: -------------------------------------------------------------------------------- 1 | [org 0x100] 2 | 3 | jmp start 4 | 5 | data: dw 60, 55, 45, 50 6 | swapflag: db 0 7 | 8 | 9 | swap: 10 | mov ax, [bx + si] ; this changes ax 11 | xchg ax, [bx + si + 2] 12 | mov [bx + si], ax 13 | 14 | ret 15 | 16 | 17 | bubblesort: 18 | dec cx 19 | shl cx, 1 ; This changes cx 20 | 21 | mainloop: 22 | mov si, 0 ; This changes si 23 | mov byte[swapflag], 0 24 | 25 | innerloop: 26 | mov ax, [bx + si] ; This changes ax 27 | cmp ax, [bx + si + 2] 28 | jbe noswap 29 | 30 | call swap ; another call here 31 | mov byte[swapflag], 1 32 | 33 | noswap: 34 | add si, 2 35 | cmp si, cx 36 | jne innerloop 37 | 38 | cmp byte[swap], 1 39 | je mainloop 40 | 41 | ret ; notice this!! 42 | 43 | 44 | 45 | 46 | start: 47 | mov bx, data 48 | mov cx, 4 49 | 50 | ; make a function call 51 | call bubblesort 52 | 53 | ; data is now sorted! 54 | 55 | mov ax, 0x4c00 56 | int 0x21 -------------------------------------------------------------------------------- /c06-03.asm: -------------------------------------------------------------------------------- 1 | [org 0x100] 2 | 3 | jmp start 4 | 5 | data: dw 60, 55, 45, 50 6 | swapflag: db 0 7 | 8 | 9 | swap: 10 | push ax ; -------------------------; 11 | ; push cx ; ------------------; ; 12 | ; ; 13 | mov ax, [bx + si] ; ; 14 | xchg ax, [bx + si + 2] ; ; 15 | mov [bx + si], ax ; ; 16 | ; ; 17 | dec cx ; ; 18 | ; do some storage here ; ; 19 | ; pop cx ; ------------------; ; 20 | pop ax ; -------------------------; 21 | 22 | ret 23 | 24 | 25 | bubblesort: 26 | push ax ; three new pushes 27 | push cx 28 | push si 29 | 30 | 31 | dec cx 32 | shl cx, 1 33 | 34 | mainloop: 35 | mov si, 0 ; use as array index 36 | mov byte[swapflag], 0 ; reset swap flag for this iteration 37 | 38 | innerloop: 39 | mov ax, [bx + si] 40 | cmp ax, [bx + si + 2] 41 | jbe noswap 42 | 43 | call swap ; another call here 44 | mov byte[swapflag], 1 45 | 46 | noswap: 47 | add si, 2 48 | cmp si, cx 49 | jne innerloop 50 | 51 | cmp byte[swap], 1 52 | je mainloop 53 | 54 | 55 | ; pops in reverse order 56 | pop si 57 | pop cx 58 | pop ax 59 | ret ; notice this!! 60 | 61 | 62 | 63 | 64 | start: 65 | mov bx, data 66 | mov cx, 4 67 | 68 | ; make a function call 69 | call bubblesort 70 | 71 | ; data is now sorted! 72 | 73 | mov ax, 0x4c00 74 | int 0x21 -------------------------------------------------------------------------------- /c06-04.asm: -------------------------------------------------------------------------------- 1 | [org 0x100] 2 | 3 | jmp start 4 | 5 | data: dw 60, 55 6 | swapflag: db 0 7 | 8 | 9 | swap: 10 | push ax ; -----------------------; 11 | ; 12 | mov ax, [bx + si] ; 13 | xchg ax, [bx + si + 2] ; 14 | mov [bx + si], ax ; 15 | ; 16 | pop ax ; -----------------------; 17 | 18 | ret 19 | 20 | 21 | bubblesort: 22 | ; handle stack issue for parameters ------------- 23 | push bp 24 | mov bp, sp 25 | 26 | push ax 27 | push bx 28 | push cx 29 | push si 30 | 31 | mov bx, [bp + 6] ; address of data to sort 32 | mov cx, [bp + 4] ; number of elements to sort 33 | 34 | ; same old code from here ----------------------- 35 | dec cx 36 | shl cx, 1 37 | 38 | mainloop: 39 | mov si, 0 ; use as array index 40 | mov byte[swapflag], 0 ; reset swap flag for this iteration 41 | 42 | innerloop: 43 | mov ax, [bx + si] 44 | cmp ax, [bx + si + 2] 45 | jbe noswap 46 | 47 | call swap ; another call here 48 | mov byte[swapflag], 1 49 | 50 | noswap: 51 | add si, 2 52 | cmp si, cx 53 | jne innerloop 54 | 55 | cmp byte[swap], 1 56 | je mainloop 57 | 58 | 59 | ; handle parameter stack issue at end again ------------------- 60 | pop si 61 | pop cx 62 | pop bx ; check removal 63 | ; pop ax 64 | pop bp ; bp was the first thing pushed, so last popped! 65 | ; stack cleared? ---------------------------------------------- 66 | 67 | ret 4 ; what is this guy? 68 | 69 | 70 | 71 | start: 72 | mov bx, data 73 | mov cx, 2 74 | 75 | push bx 76 | push cx 77 | ; make a function call 78 | call bubblesort 79 | 80 | ; data is now sorted! 81 | 82 | mov ax, 0x4c00 83 | int 0x21 -------------------------------------------------------------------------------- /c06-05.asm: -------------------------------------------------------------------------------- 1 | [org 0x100] 2 | 3 | jmp start 4 | 5 | data: dw 60, 55 6 | ; swapflag: db 0 ; Globals are bad! Let's make this local. 7 | 8 | 9 | swap: 10 | push ax ; -----------------------; 11 | ; 12 | mov ax, [bx + si] ; 13 | xchg ax, [bx + si + 2] ; 14 | mov [bx + si], ax ; 15 | ; 16 | pop ax ; -----------------------; 17 | 18 | ret 19 | 20 | 21 | bubblesort: 22 | ; handle stack issue for parameters ------------- 23 | push bp 24 | mov bp, sp 25 | 26 | sub sp, 2 ; make space on the stack, just below BP 27 | ; only if you want to do local variables 28 | 29 | 30 | push ax 31 | push bx 32 | push cx 33 | push si 34 | 35 | mov bx, [bp + 6] ; address of data to sort 36 | mov cx, [bp + 4] ; number of elements to sort 37 | 38 | ; same old code from here ----------------------- 39 | dec cx 40 | shl cx, 1 41 | 42 | mainloop: 43 | mov si, 0 ; use as array index 44 | ; mov byte[swapflag], 0 ; reset swap flag for this iteration 45 | mov word [bp - 2], 0 ; has to be a word 46 | 47 | innerloop: 48 | mov ax, [bx + si] 49 | cmp ax, [bx + si + 2] 50 | jbe noswap 51 | 52 | call swap ; another call here 53 | ; mov byte[swapflag], 1 54 | mov word [bp - 2], 1 55 | 56 | noswap: 57 | add si, 2 58 | cmp si, cx 59 | jne innerloop 60 | 61 | cmp word [bp - 2], 1 62 | je mainloop 63 | 64 | 65 | ; handle parameter stack issue at end again ------------------- 66 | pop si 67 | pop cx 68 | pop bx 69 | pop ax 70 | 71 | mov sp, bp ; sp should be restored 72 | 73 | pop bp ; bp was the first thing pushed, so last popped! 74 | ; stack cleared? ---------------------------------------------- 75 | 76 | ret 4 ; what is this guy? 77 | 78 | 79 | 80 | start: 81 | mov bx, data 82 | mov cx, 2 83 | 84 | push bx 85 | push cx 86 | ; make a function call 87 | call bubblesort 88 | 89 | ; data is now sorted! 90 | 91 | mov ax, 0x4c00 92 | int 0x21 -------------------------------------------------------------------------------- /c07-01.asm: -------------------------------------------------------------------------------- 1 | [org 0x0100] 2 | 3 | mov ax, 0xb800 ; video memory base 4 | mov es, ax ; cannot move to es through IMM 5 | mov di, 0 ; top left location 6 | 7 | nextpos: 8 | mov word [es:di], 0x0776 ; 0x07 -- full white (try 41) 9 | ; 0x20 is the space character 10 | add di, 2 11 | cmp di, 4000 12 | jne nextpos 13 | 14 | mov ax, 0x4c00 15 | int 0x21 -------------------------------------------------------------------------------- /c07-02.asm: -------------------------------------------------------------------------------- 1 | [org 0x0100] 2 | 3 | jmp start 4 | 5 | message: db 'hello world' 6 | length: dw 11 7 | 8 | clrscr: 9 | push es 10 | push ax 11 | push di 12 | 13 | mov ax, 0xb800 14 | mov es, ax 15 | mov di, 0 16 | 17 | nextloc: 18 | mov word [es:di], 0x0720 19 | add di, 2 20 | cmp di, 4000 21 | jne nextloc 22 | 23 | pop di 24 | pop ax 25 | pop es 26 | ret 27 | 28 | 29 | printstr: 30 | push bp 31 | mov bp, sp 32 | push es 33 | push ax 34 | push cx 35 | push si 36 | push di 37 | 38 | mov ax, 0xb800 39 | mov es, ax 40 | mov di, 0 41 | 42 | 43 | mov si, [bp + 6] 44 | mov cx, [bp + 4] 45 | mov ah, 0x07 ; only need to do this once 46 | 47 | nextchar: 48 | mov al, [si] 49 | mov [es:di], ax 50 | add di, 2 51 | add si, 1 52 | 53 | ; dec cx 54 | ; jnz nextchar 55 | 56 | ; alternatively 57 | loop nextchar 58 | 59 | 60 | pop di 61 | pop si 62 | pop cx 63 | pop ax 64 | pop es 65 | pop bp 66 | ret 4 67 | 68 | 69 | start: 70 | call clrscr 71 | 72 | mov ax, message 73 | push ax 74 | push word [length] 75 | call printstr 76 | 77 | 78 | 79 | ; wait for keypress 80 | mov ah, 0x1 ; input char is 0x1 in ah 81 | int 0x21 82 | 83 | mov ax, 0x4c00 84 | int 0x21 85 | -------------------------------------------------------------------------------- /c07-03.asm: -------------------------------------------------------------------------------- 1 | [org 0x0100] 2 | 3 | jmp start 4 | 5 | clrscr: 6 | push es 7 | push ax 8 | push di 9 | 10 | mov ax, 0xb800 11 | mov es, ax 12 | mov di, 0 13 | 14 | nextloc: 15 | mov word [es:di], 0x0720 16 | add di, 2 17 | cmp di, 4000 18 | jne nextloc 19 | 20 | pop di 21 | pop ax 22 | pop es 23 | ret 24 | 25 | 26 | printnum: 27 | push bp 28 | mov bp, sp 29 | push es 30 | push ax 31 | push bx 32 | push cx 33 | push dx 34 | push di 35 | 36 | ; first, let's split digits and push them onto the stack 37 | 38 | mov ax, [bp+4] ; number to print 39 | mov bx, 10 ; division base 10 40 | mov cx, 0 ; total digit counter 41 | 42 | nextdigit: 43 | mov dx, 0 ; zero out 44 | div bx ; divides ax/bx .. quotient in ax, remainder in dl 45 | add dl, 0x30 ; convert to ASCII 46 | push dx ; push to stack for later printing 47 | inc cx ; have another digit 48 | cmp ax, 0 ; is there something in quotient? 49 | jnz nextdigit 50 | 51 | ; now let's do the printing 52 | 53 | mov ax, 0xb800 54 | mov es, ax 55 | 56 | mov di, 0 57 | nextpos: 58 | pop dx ; digit to output. Already in ASCII 59 | mov dh, 0x04 ; why is this inside the loop here? 60 | mov [es:di], dx 61 | add di, 2 62 | loop nextpos ; cx has already been set, use that 63 | 64 | pop di 65 | pop dx 66 | pop cx 67 | pop bx 68 | pop ax 69 | pop es 70 | pop bp 71 | ret 2 72 | 73 | 74 | 75 | start: 76 | call clrscr 77 | 78 | mov ax, 452 79 | push ax 80 | call printnum 81 | 82 | 83 | ; wait for keypress 84 | mov ah, 0x1 ; input char is 0x1 in ah 85 | int 0x21 86 | 87 | mov ax, 0x4c00 88 | int 0x21 89 | -------------------------------------------------------------------------------- /c07-04.asm: -------------------------------------------------------------------------------- 1 | [org 0x0100] 2 | jmp start 3 | 4 | clrscr: 5 | push es 6 | push ax 7 | push cx 8 | push di 9 | 10 | mov ax, 0xb800 ; same as before 11 | mov es, ax 12 | 13 | xor di, di ; starting at index 0 14 | 15 | mov ax, 0x0720 ; what to write 16 | mov cx, 2000 ; how many times to write 17 | ; holds the count, NOT bytes! 18 | 19 | cld ; auto-increment 20 | rep stosw ; automatically writes starting from [es:di] 21 | 22 | pop di 23 | pop cx 24 | pop ax 25 | pop es 26 | ret 27 | 28 | start: 29 | call clrscr 30 | mov ax, 0x4c00 31 | int 0x21 32 | -------------------------------------------------------------------------------- /c08-01.asm: -------------------------------------------------------------------------------- 1 | [org 0x0100] 2 | 3 | jmp start 4 | 5 | clrscr: 6 | push es 7 | push ax 8 | push cx 9 | push di 10 | 11 | mov ax, 0xb800 12 | mov es, ax 13 | xor di, di 14 | mov ax, 0x0765 15 | mov cx, 2000 16 | 17 | cld ; auto-increment mode 18 | rep stosw ; rep cx times, store words 19 | ; source is ax for word, al for bytes 20 | ; destination is es:di 21 | ; inc/dec di as well by 2 bytes 22 | 23 | pop di 24 | pop cx 25 | pop ax 26 | pop es 27 | ret 28 | 29 | 30 | start: 31 | 32 | call clrscr 33 | mov ax, 0x4c00 34 | int 0x21 -------------------------------------------------------------------------------- /c08-02.asm: -------------------------------------------------------------------------------- 1 | [org 0x0100] 2 | 3 | jmp start 4 | 5 | message: db 'hello world', 0 6 | 7 | clrscr: 8 | push es 9 | push ax 10 | push cx 11 | push di 12 | 13 | mov ax, 0xb800 14 | mov es, ax 15 | xor di, di 16 | mov ax, 0x0720 17 | mov cx, 2000 18 | 19 | cld ; auto-increment mode 20 | rep stosw ; rep cx times, store words 21 | ; source is ax for word, al for bytes 22 | ; destination is es:di 23 | ; inc/dec di as well by 2 bytes 24 | 25 | pop di 26 | pop cx 27 | pop ax 28 | pop es 29 | ret 30 | 31 | printnum: 32 | push bp 33 | mov bp, sp 34 | push es 35 | push ax 36 | push bx 37 | push cx 38 | push dx 39 | push di 40 | 41 | ; first, let's split digits and push them onto the stack 42 | 43 | mov ax, [bp+4] ; number to print 44 | mov bx, 10 ; division base 10 45 | mov cx, 0 ; total digit counter 46 | 47 | nextdigit: 48 | mov dx, 0 ; zero out 49 | div bx ; divides ax/bx .. quotient in ax, remainder in dl 50 | add dl, 0x30 ; convert to ASCII 51 | push dx ; push to stack for later printing 52 | inc cx ; have another digit 53 | cmp ax, 0 ; is there something in quotient? 54 | jnz nextdigit 55 | 56 | ; now let's do the printing 57 | 58 | mov ax, 0xb800 59 | mov es, ax 60 | 61 | mov di, 0 62 | nextpos: 63 | pop dx ; digit to output. Already in ASCII 64 | mov dh, 0x07 ; why is this inside the loop here? 65 | mov [es:di], dx 66 | add di, 2 67 | loop nextpos ; cx has already been set, use that 68 | 69 | pop di 70 | pop dx 71 | pop cx 72 | pop bx 73 | pop ax 74 | pop es 75 | pop bp 76 | ret 2 77 | 78 | 79 | strlen: 80 | push bp 81 | mov bp,sp 82 | push es 83 | push cx 84 | push di 85 | 86 | les di, [bp+4] ; load DI from BP+4 and ES from BP+6 87 | mov cx, 0xffff ; maximum possible length 88 | 89 | xor al, al ; value to find 90 | repne scasb ; repeat until scan does not become NE to AL 91 | ; decrement CX each time 92 | 93 | mov ax, 0xffff 94 | sub ax, cx ; find how many times CX was decremented 95 | 96 | dec ax ; exclude null from the length 97 | 98 | pop di 99 | pop cx 100 | pop es 101 | pop bp 102 | ret 4 103 | 104 | 105 | start: 106 | call clrscr 107 | 108 | push ds 109 | mov ax, message 110 | push ax 111 | call strlen ; return value is in AX 112 | 113 | push ax 114 | call printnum ; print out the length 115 | 116 | 117 | mov ah, 0x1 118 | int 0x21 119 | mov ax, 0x4c00 120 | int 0x21 -------------------------------------------------------------------------------- /c09-01.asm: -------------------------------------------------------------------------------- 1 | SECTION .DATA 2 | hello: db 'Hello from ASM!',10 3 | helloLen: equ $-hello 4 | 5 | SECTION .TEXT 6 | GLOBAL say_hi 7 | 8 | 9 | say_hi: 10 | mov rax, rdi ; first param goes in RDI 11 | push rax ; save the value sent to us 12 | 13 | mov eax, 4 ; write() 14 | mov ebx, 1 ; STDOUT 15 | mov ecx, hello 16 | mov edx, helloLen 17 | 18 | int 80h ; Interrupt 19 | 20 | pop rax ; get the value sent to us 21 | inc rax ; increment it 22 | ret ; return val is in rax 23 | 24 | 25 | 26 | # Assemble using: nasm -f elf64 c09-01.asm -o c09-01-asm.o -------------------------------------------------------------------------------- /c09-01.c: -------------------------------------------------------------------------------- 1 | /* example.c */ 2 | #include 3 | extern int say_hi(); 4 | 5 | 6 | int main(int argc, char *argv[]) { 7 | int val; 8 | 9 | printf("Hello from C! \n"); 10 | val = say_hi(5); 11 | printf("Value returned: %d \n", val); 12 | } 13 | 14 | 15 | 16 | // Compile and link using: gcc -no-pie c09-01.c c09-01-asm.o -o hello -------------------------------------------------------------------------------- /c10-01.sh: -------------------------------------------------------------------------------- 1 | 2 | # ---------------------------- 3 | # Cross-Compilation Tutorial 4 | # ---------------------------- 5 | 6 | 7 | - Write the code 8 | cd /tmp 9 | mkdir risc 10 | vi HelloWorld.s 11 | 12 | # --------------- start of program 13 | # Source: https://smist08.wordpress.com/2019/09/07/risc-v-assembly-language-hello-world/ 14 | 15 | # Risc-V Assembler program to print "Hello World!" 16 | # to stdout. 17 | # 18 | # a0-a2 - parameters to linux function services 19 | # a7 - linux function number 20 | # 21 | 22 | .global _start # Provide program starting address to linker 23 | 24 | # Setup the parameters to print hello world 25 | # and then call Linux to do it. 26 | 27 | _start: addi a0, x0, 1 # 1 = StdOut 28 | la a1, helloworld # load address of helloworld 29 | addi a2, x0, 13 # length of our string 30 | addi a7, x0, 64 # linux write system call 31 | ecall # Call linux to output the string 32 | 33 | # Setup the parameters to exit the program 34 | # and then call Linux to do it. 35 | 36 | addi a0, x0, 0 # Use 0 return code 37 | addi a7, x0, 93 # Service command code 93 terminates 38 | ecall # Call linux to terminate the program 39 | 40 | .data 41 | helloworld: .ascii "Hello World!\n" 42 | # --------------- end of program 43 | 44 | 45 | 46 | - Cross-Compile for RISCV 47 | - Download GNU cross-compilation tools (https://wiki.debian.org/RISC-V#Cross_compilation) 48 | 49 | sudo dpkg --add-architecture riscv64 50 | sudo apt-get install gcc-riscv64-linux-gnu g++-riscv64-linux-gnu 51 | sudo sh -c "cat >/etc/ld.so.conf.d/riscv64-linux-gnu.conf <