From ad139585b6f370c8effbec9f7d4408e25ad46297 Mon Sep 17 00:00:00 2001
From: Daniel Kibblewhite <daniel2.kibblewhite@live.uwe.ac.uk>
Date: Tue, 12 Nov 2024 14:47:23 +0000
Subject: [PATCH] updated task 2 just md to complete then build

---
 ws1/makefile                  |  13 -
 ws1/src/Makefile              |  17 ++
 ws1/src/task2_test/asm_io.asm | 503 ++++++++++++++++++++++++++++++++++
 ws1/src/task2_test/asm_io.inc |  30 ++
 ws1/src/task2_test/driver.c   |   6 +
 ws1/src/task2_test/task2.asm  | 161 +++++++++++
 6 files changed, 717 insertions(+), 13 deletions(-)
 delete mode 100644 ws1/makefile
 create mode 100644 ws1/src/Makefile
 create mode 100644 ws1/src/task2_test/asm_io.asm
 create mode 100644 ws1/src/task2_test/asm_io.inc
 create mode 100644 ws1/src/task2_test/driver.c
 create mode 100644 ws1/src/task2_test/task2.asm

diff --git a/ws1/makefile b/ws1/makefile
deleted file mode 100644
index 96a76c4..0000000
--- a/ws1/makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-all: task1
-
-task1: task1.o asm_io.o driver.o
-    gcc -m32 -o task1 task1.o asm_io.o driver.o
-
-task1.o: task1.asm
-    nasm -f elf task1.asm -o task1.o
-
-asm_io.o: asm_io.asm
-    nasm -f elf asm_io.asm -o asm_io.o
-
-driver.o: driver.c
-    gcc -m32 -c driver.c -o driver.o
diff --git a/ws1/src/Makefile b/ws1/src/Makefile
new file mode 100644
index 0000000..4ce6c43
--- /dev/null
+++ b/ws1/src/Makefile
@@ -0,0 +1,17 @@
+# Makefile for building task2 program from assembly and C in the current directory
+
+# Target to build task2 executable
+task2: driver2.o task2.o asm_io.o
+    gcc -m32 driver2.o task2.o asm_io.o -o task2
+
+# Assemble task2.asm
+task2.o: task2.asm
+    nasm -f elf task2.asm -o task2.o
+
+# Assemble asm_io.asm
+asm_io.o: asm_io.asm
+    nasm -f elf asm_io.asm -o asm_io.o
+
+# Compile driver2.c
+driver2.o: driver2.c
+    gcc -m32 -c driver2.c -o driver2.o
diff --git a/ws1/src/task2_test/asm_io.asm b/ws1/src/task2_test/asm_io.asm
new file mode 100644
index 0000000..1fcdaf6
--- /dev/null
+++ b/ws1/src/task2_test/asm_io.asm
@@ -0,0 +1,503 @@
+;
+; file: asm_io.asm
+; Assembly I/O routines
+; To assemble for DJGPP
+;   nasm -f coff -d COFF_TYPE asm_io.asm
+; To assemble for Borland C++ 5.x
+;   nasm -f obj -d OBJ_TYPE asm_io.asm
+; To assemble for Microsoft Visual Studio
+;   nasm -f win32 -d COFF_TYPE asm_io.asm
+; To assemble for Linux
+;   nasm -f elf -d ELF_TYPE asm_io.asm
+; To assemble for Watcom
+;   nasm -f obj -d OBJ_TYPE -d WATCOM asm_io.asm
+; IMPORTANT NOTES FOR WATCOM
+;   The Watcom compiler's C library does not use the
+;   standard C calling convention. For example, the
+;   putchar() function gets its argument from the
+;   the value of EAX, not the stack.
+
+
+%define NL 10
+%define CF_MASK 00000001h
+%define PF_MASK 00000004h
+%define AF_MASK 00000010h
+%define ZF_MASK 00000040h
+%define SF_MASK 00000080h
+%define DF_MASK 00000400h
+%define OF_MASK 00000800h
+
+
+;
+; Linux C doesn't put underscores on labels
+;
+; %ifdef ELF_TYPE
+%define _scanf   scanf
+%define _printf  printf
+%define _getchar getchar
+%define _putchar putchar
+; %endif
+
+; ;
+; ; Watcom puts underscores at end of label
+; ;
+; %ifdef WATCOM
+;   %define _scanf   scanf_
+;   %define _printf  printf
+;   %define _getchar getchar_
+;   %define _putchar putchar_
+; %endif
+
+%ifdef OBJ_TYPE
+segment .data public align=4 class=data use32
+%else
+segment .data
+%endif
+
+int_format	    db  "%i", 0
+string_format       db  "%s", 0
+reg_format	    db  "Register Dump # %d", NL
+		    db  "EAX = %.8X EBX = %.8X ECX = %.8X EDX = %.8X", NL
+                    db  "ESI = %.8X EDI = %.8X EBP = %.8X ESP = %.8X", NL
+                    db  "EIP = %.8X FLAGS = %.4X %s %s %s %s %s %s %s", NL
+	            db  0
+carry_flag	    db  "CF", 0
+zero_flag	    db  "ZF", 0
+sign_flag	    db  "SF", 0
+parity_flag	    db	"PF", 0
+overflow_flag	    db	"OF", 0
+dir_flag	    db	"DF", 0
+aux_carry_flag	    db	"AF", 0
+unset_flag	    db	"  ", 0
+mem_format1         db  "Memory Dump # %d Address = %.8X", NL, 0
+mem_format2         db  "%.8X ", 0
+mem_format3         db  "%.2X ", 0
+stack_format        db  "Stack Dump # %d", NL
+	            db  "EBP = %.8X ESP = %.8X", NL, 0
+stack_line_format   db  "%+4d  %.8X  %.8X", NL, 0
+math_format1        db  "Math Coprocessor Dump # %d Control Word = %.4X"
+                    db  " Status Word = %.4X", NL, 0
+valid_st_format     db  "ST%d: %.10g", NL, 0
+invalid_st_format   db  "ST%d: Invalid ST", NL, 0
+empty_st_format     db  "ST%d: Empty", NL, 0
+
+;
+; code is put in the _TEXT segment
+;
+%ifdef OBJ_TYPE
+segment text public align=1 class=code use32
+%else
+segment .text
+%endif
+	global	read_int, print_int, print_string, read_char
+	global  print_char, print_nl, sub_dump_regs, sub_dump_mem
+        global  sub_dump_math, sub_dump_stack
+        extern  _scanf, _printf, _getchar, _putchar
+
+read_int:
+	enter	4,0
+	pusha
+	pushf
+
+	lea	eax, [ebp-4]
+	push	eax
+	push	dword int_format
+	call	_scanf
+	pop	ecx
+	pop	ecx
+	
+	popf
+	popa
+	mov	eax, [ebp-4]
+	leave
+	ret
+
+print_int:
+	enter	0,0
+	pusha
+	pushf
+
+	push	eax
+	push	dword int_format
+	call	_printf
+	pop	ecx
+	pop	ecx
+
+	popf
+	popa
+	leave
+	ret
+
+print_string:
+	enter	0,0
+	pusha
+	pushf
+
+	push	eax
+	push    dword string_format
+	call	_printf
+	pop	ecx
+	pop	ecx
+
+	popf
+	popa
+	leave
+	ret
+
+read_char:
+	enter	4,0
+	pusha
+	pushf
+
+	call	_getchar
+	mov	[ebp-4], eax
+
+	popf
+	popa
+	mov	eax, [ebp-4]
+	leave
+	ret
+
+print_char:
+	enter	0,0
+	pusha
+	pushf
+
+%ifndef WATCOM
+	push	eax
+%endif
+	call	_putchar
+%ifndef WATCOM
+	pop	ecx
+%endif
+
+	popf
+	popa
+	leave
+	ret
+
+
+print_nl:
+	enter	0,0
+	pusha
+	pushf
+
+%ifdef WATCOM
+	mov	eax, 10		; WATCOM doesn't use the stack here
+%else
+	push	dword 10	; 10 == ASCII code for \n
+%endif
+	call	_putchar
+%ifndef WATCOM
+	pop	ecx
+%endif
+	popf
+	popa
+	leave
+	ret
+
+
+sub_dump_regs:
+	enter   4,0
+	pusha
+	pushf
+	mov     eax, [esp]      ; read FLAGS back off stack
+	mov	[ebp-4], eax    ; save flags
+
+;
+; show which FLAGS are set
+;
+	test	eax, CF_MASK
+	jz	cf_off
+	mov	eax, carry_flag
+	jmp	short push_cf
+cf_off:
+	mov	eax, unset_flag
+push_cf:
+	push	eax
+
+	test	dword [ebp-4], PF_MASK
+	jz	pf_off
+	mov	eax, parity_flag
+	jmp	short push_pf
+pf_off:
+	mov	eax, unset_flag
+push_pf:
+	push	eax
+
+	test	dword [ebp-4], AF_MASK
+	jz	af_off
+	mov	eax, aux_carry_flag
+	jmp	short push_af
+af_off:
+	mov	eax, unset_flag
+push_af:
+	push	eax
+
+	test	dword [ebp-4], ZF_MASK
+	jz	zf_off
+	mov	eax, zero_flag
+	jmp	short push_zf
+zf_off:
+	mov	eax, unset_flag
+push_zf:
+	push	eax
+
+	test	dword [ebp-4], SF_MASK
+	jz	sf_off
+	mov	eax, sign_flag
+	jmp	short push_sf
+sf_off:
+	mov	eax, unset_flag
+push_sf:
+	push	eax
+
+	test	dword [ebp-4], DF_MASK
+	jz	df_off
+	mov	eax, dir_flag
+	jmp	short push_df
+df_off:
+	mov	eax, unset_flag
+push_df:
+	push	eax
+
+	test	dword [ebp-4], OF_MASK
+	jz	of_off
+	mov	eax, overflow_flag
+	jmp	short push_of
+of_off:
+	mov	eax, unset_flag
+push_of:
+	push	eax
+
+	push    dword [ebp-4]   ; FLAGS
+	mov	eax, [ebp+4]
+	sub	eax, 10         ; EIP on stack is 10 bytes ahead of orig
+	push	eax             ; EIP
+	lea     eax, [ebp+12]
+	push    eax             ; original ESP
+	push    dword [ebp]     ; original EBP
+        push    edi
+        push    esi
+	push    edx
+	push	ecx
+	push	ebx
+	push	dword [ebp-8]   ; original EAX
+	push	dword [ebp+8]   ; # of dump
+	push	dword reg_format
+	call	_printf
+	add	esp, 76
+	popf
+	popa
+	leave
+	ret     4
+
+sub_dump_stack:
+	enter   0,0
+	pusha
+	pushf
+
+	lea     eax, [ebp+20]
+	push    eax             ; original ESP
+	push    dword [ebp]     ; original EBP
+	push	dword [ebp+8]   ; # of dump
+	push	dword stack_format
+	call	_printf
+	add	esp, 16
+
+	mov	ebx, [ebp]	; ebx = original ebp
+	mov	eax, [ebp+16]   ; eax = # dwords above ebp
+	shl	eax, 2          ; eax *= 4
+	add	ebx, eax	; ebx = & highest dword in stack to display
+	mov	edx, [ebp+16]
+	mov	ecx, edx
+	add	ecx, [ebp+12]
+	inc	ecx		; ecx = # of dwords to display
+
+stack_line_loop:
+	push	edx
+	push	ecx		; save ecx & edx
+
+	push	dword [ebx]	; value on stack
+	push	ebx		; address of value on stack
+	mov	eax, edx
+	sal	eax, 2		; eax = 4*edx
+	push	eax		; offset from ebp
+	push	dword stack_line_format
+	call	_printf
+	add	esp, 16
+
+	pop	ecx
+	pop	edx
+
+	sub	ebx, 4
+	dec	edx
+	loop	stack_line_loop
+
+	popf
+	popa
+	leave
+	ret     12
+
+
+sub_dump_mem:
+	enter	0,0
+	pusha
+	pushf
+
+	push	dword [ebp+12]
+	push	dword [ebp+16]
+	push	dword mem_format1
+	call	_printf
+	add	esp, 12		
+	mov	esi, [ebp+12]      ; address
+	and	esi, 0FFFFFFF0h    ; move to start of paragraph
+	mov	ecx, [ebp+8]
+	inc	ecx
+mem_outer_loop:
+	push	ecx
+	push	esi
+	push	dword mem_format2
+	call	_printf
+	add	esp, 8
+
+	xor	ebx, ebx
+mem_hex_loop:
+	xor	eax, eax
+	mov	al, [esi + ebx]
+	push	eax
+	push	dword mem_format3
+	call	_printf
+	add	esp, 8
+	inc	ebx
+	cmp	ebx, 16
+	jl	mem_hex_loop
+	
+	mov	eax, '"'
+	call	print_char
+	xor	ebx, ebx
+mem_char_loop:
+	xor	eax, eax
+	mov	al, [esi+ebx]
+	cmp	al, 32
+	jl	non_printable
+	cmp	al, 126
+	jg	non_printable
+	jmp	short mem_char_loop_continue
+non_printable:
+	mov	eax, '?'
+mem_char_loop_continue:
+	call	print_char
+
+	inc	ebx
+	cmp	ebx, 16
+	jl	mem_char_loop
+
+	mov	eax, '"'
+	call	print_char
+	call	print_nl
+
+	add	esi, 16
+	pop	ecx
+	loop	mem_outer_loop
+
+	popf
+	popa
+	leave
+	ret	12
+
+; function sub_dump_math
+;   prints out state of math coprocessor without modifying the coprocessor
+;   or regular processor state
+; Parameters:
+;  dump number - dword at [ebp+8]
+; Local variables:
+;   ebp-108 start of fsave buffer
+;   ebp-116 temp double
+; Notes: This procedure uses the Pascal convention.
+;   fsave buffer structure:
+;   ebp-108   control word
+;   ebp-104   status word
+;   ebp-100   tag word
+;   ebp-80    ST0
+;   ebp-70    ST1
+;   ebp-60    ST2 ...
+;   ebp-10    ST7
+;
+sub_dump_math:
+	enter	116,0
+	pusha
+	pushf
+
+	fsave	[ebp-108]	; save coprocessor state to memory
+	mov	eax, [ebp-104]  ; status word
+	and	eax, 0FFFFh
+	push	eax
+	mov	eax, [ebp-108]  ; control word
+	and	eax, 0FFFFh
+	push	eax
+	push	dword [ebp+8]
+	push	dword math_format1
+	call	_printf
+	add	esp, 16
+;
+; rotate tag word so that tags in same order as numbers are
+; in the stack
+;
+	mov	cx, [ebp-104]	; ax = status word
+	shr	cx, 11
+	and	cx, 7           ; cl = physical state of number on stack top
+	mov	bx, [ebp-100]   ; bx = tag word
+	shl     cl,1		; cl *= 2
+	ror	bx, cl		; move top of stack tag to lowest bits
+
+	mov	edi, 0		; edi = stack number of number
+	lea	esi, [ebp-80]   ; esi = address of ST0
+	mov	ecx, 8          ; ecx = loop counter
+tag_loop:
+	push	ecx
+	mov	ax, 3
+	and	ax, bx		; ax = current tag
+	or	ax, ax		; 00 -> valid number
+	je	valid_st
+	cmp	ax, 1		; 01 -> zero
+	je	zero_st
+	cmp	ax, 2		; 10 -> invalid number
+	je	invalid_st
+	push	edi		; 11 -> empty
+	push	dword empty_st_format
+	call	_printf
+	add	esp, 8
+	jmp	short cont_tag_loop
+zero_st:
+	fldz
+	jmp	short print_real
+valid_st:
+	fld	tword [esi]
+print_real:
+	fstp	qword [ebp-116]
+	push	dword [ebp-112]
+	push	dword [ebp-116]
+	push	edi
+	push	dword valid_st_format
+	call	_printf
+	add	esp, 16
+	jmp	short cont_tag_loop
+invalid_st:
+	push	edi
+	push	dword invalid_st_format
+	call	_printf
+	add	esp, 8
+cont_tag_loop:
+	ror	bx, 2		; mov next tag into lowest bits
+	inc	edi
+	add	esi, 10         ; mov to next number on stack
+	pop	ecx
+	loop    tag_loop
+
+	frstor	[ebp-108]       ; restore coprocessor state
+	popf
+	popa
+	leave
+	ret	4
+
diff --git a/ws1/src/task2_test/asm_io.inc b/ws1/src/task2_test/asm_io.inc
new file mode 100644
index 0000000..9163be3
--- /dev/null
+++ b/ws1/src/task2_test/asm_io.inc
@@ -0,0 +1,30 @@
+	extern  read_int, print_int, print_string
+	extern	read_char, print_char, print_nl
+	extern  sub_dump_regs, sub_dump_mem, sub_dump_math, sub_dump_stack
+
+%macro 	dump_regs 1
+	push	  dword %1
+	call	  sub_dump_regs
+%endmacro
+
+
+;
+; usage: dump_mem label, start-address, # paragraphs
+%macro  dump_mem 3
+	push	 dword %1
+	push	 dword %2
+	push	 dword %3
+	call	 sub_dump_mem
+%endmacro
+
+%macro	dump_math 1
+	push	 dword %1
+	call	 sub_dump_math
+%endmacro
+
+%macro  dump_stack 3
+	push	 dword %3
+        push     dword %2
+	push	 dword %1
+        call     sub_dump_stack
+%endmacro
\ No newline at end of file
diff --git a/ws1/src/task2_test/driver.c b/ws1/src/task2_test/driver.c
new file mode 100644
index 0000000..1c33ae5
--- /dev/null
+++ b/ws1/src/task2_test/driver.c
@@ -0,0 +1,6 @@
+int __attribute__((cdecl)) asm_main( void );
+int main() {
+int ret_status;
+ret_status = asm_main();
+return ret_status;
+}
\ No newline at end of file
diff --git a/ws1/src/task2_test/task2.asm b/ws1/src/task2_test/task2.asm
new file mode 100644
index 0000000..e958ba0
--- /dev/null
+++ b/ws1/src/task2_test/task2.asm
@@ -0,0 +1,161 @@
+%include "./asm_io.inc"    ; Include I/O library for all I/O operations
+
+; --- Data Segment ---
+
+segment .data
+    welcome_msg db "Hello Thanks for playing - may the ods ever be in your favour, ", 0 ; Welcome message string
+    prompt_name db "Please enter your Name (mine is Bob): ", 0 ; Prompt message for entering name
+    prompt_count db "Enter number of times to print (between 50 and 100): ", 0 ; Prompt for number of repetitions
+    prompt_start db "Enter the start of the range (1 to 100): ", 0 ; Prompt for range start
+    prompt_end db "Enter the end of the range (1 to 100): ", 0 ; Prompt for range end
+    range_error_msg db "Error: Invalid range.", 0 ; Error message for invalid range
+    sum_result_msg db "The sum of numbers in the range is: ", 0 ; Result message for range sum
+    error_msg db "Error: Number must be between 50 and 100.", 0 ; Error message for invalid count
+    newline db 10, 0 ; Newline character
+
+; --- BSS Segment ---
+
+segment .bss
+    name resb 30 ; Reserve 30 bytes for storing the user's name
+    count resd 1 ; Reserve space for storing the count
+    array resd 100 ; Reserve space for 100 integers
+    sum resd 1 ; Reserve space for the calculated sum
+    start_range resd 1 ; Reserve space for the start of the range
+    end_range resd 1 ; Reserve space for the end of the range
+
+; --- Code Segment ---
+
+segment .text
+    global asm_main ; Make asm_main accessible externally
+
+asm_main:
+    pusha ; Save the current state of all general-purpose registers
+
+    ; --- Prompt for entering and reading the user’s name ---
+    
+    mov eax, prompt_name ; Load prompt_name address into EAX
+    call print_string ; Display the name prompt
+    mov edi, name ; Move address to store the name into EDI
+    mov ecx, 30 ; Set loop counter to 30 for name input length
+    xor al, al ; Clear AL for storing characters
+
+read_name_loop:
+    call read_char ; Read a character from the user
+    cmp al, 10 ; Compare with newline character
+    je name_input_complete ; If newline, finish input
+    stosb ; Store the character in AL to the memory at EDI
+    loop read_name_loop ; Repeat for all characters
+
+name_input_complete:
+    mov byte [edi], 0 ; Null-terminate the user's inputted name
+
+    ; --- Prompt for entering and reading the count ---
+    
+    mov eax, prompt_count ; Load address of prompt_count into EAX
+    call print_string ; Display the count prompt
+    call read_int ; Read the integer input
+    mov [count], eax ; Store the user's inputted count
+
+    ; --- Validating count ---
+    
+    mov eax, [count] ; Move count into EAX for validation
+    cmp eax, 50 ; Compare count with 50
+    jl display_error ; Jump to error if less than 50
+    cmp eax, 100 ; Compare count with 100
+    jg display_error ; Jump to error if greater than 100
+
+    ; --- Loop for printing the welcome message ---
+    
+    mov ecx, eax ; Load count into ECX as loop counter
+
+print_welcome:
+    mov eax, welcome_msg ; Load address of welcome_msg into EAX
+    call print_string ; Print the welcome message
+    mov eax, name ; Load address of name into EAX
+    call print_string ; Print the user's name
+    call print_nl ; Print a newline after each message
+    loop print_welcome ; Repeat for count times
+
+    ; --- Initialise my array with values from 1 to 100 ---
+
+    mov ecx, 100 ; Set loop counter `ECX` to 100
+    mov eax, 1 ; Start with the number 1
+    mov ebx, array ; Point `EBX` to the start of the array (index 0)
+
+initialise_array:
+    mov [ebx], eax ; Store the value in `EAX` at address `EBX`
+    inc eax ; Increment `EAX` to the next number
+    add ebx, 4 ; Move `EBX` 4 bytes forward to the next integer
+    dec ecx ; Decrement loop counter `ECX`
+    cmp ecx, 0 ; Check if `ECX` is zero
+    jne initialise_array ; Repeat until all values are stored
+
+    ; --- Prompt for the range input ---
+    
+    mov eax, prompt_start ; Load prompt for start of range into EAX
+    call print_string ; Display the start range prompt
+    call read_int ; Read the start range input
+    mov [start_range], eax ; Store the start of the range
+    
+    mov eax, prompt_end ; Load prompt for end of range into EAX
+    call print_string ; Display the end range prompt
+    call read_int ; Read the end range input
+    mov [end_range], eax ; Store the end of the range
+
+    ; --- Validate the range ---
+
+    mov eax, [start_range] ; Load start_range into EAX
+    cmp eax, 1 ; Ensure start_range is at least 1
+    jl range_error ; Jump to error if less than 1
+    mov ebx, [end_range] ; Load end_range into EBX
+    cmp ebx, 100 ; Ensure end_range is at most 100
+    jg range_error ; Jump to error if more than 100
+    cmp eax, ebx ; Ensure start is less than or equal to end
+    jg range_error ; Jump to error if invalid range
+
+    ; --- Summing the array within the given range ---
+
+    mov ecx, eax ; Load start_range as starting index into ECX
+    dec ecx ; Convert to zero-based index
+    mov ebx, [end_range] ; Load end_range to EBX
+    sub ebx, eax ; Calculate the range length
+    inc ebx ; Adjust range to include endpoint
+    mov edx, 0 ; Initialize sum accumulator in EDX
+    lea edi, [array] ; Load base address of array into EDI
+
+sum_array:
+    add edx, [edi + ecx*4] ; Add current element to sum
+    inc ecx ; Move to next index
+    dec ebx ; Decrement range length
+    jnz sum_array ; Repeat until range is covered
+
+    mov [sum], edx ; Store the calculated sum
+
+    ; --- Display the result of sum within range ---
+    
+    mov eax, sum_result_msg ; Load result message into EAX
+    call print_string ; Display the result message
+    mov eax, [sum] ; Load calculated sum into EAX
+    call print_int ; Print the sum
+    call print_nl ; Print a newline
+
+    ; --- Programme exit point ---
+    
+    popa ; Restore original values of registers
+    ret ; Return from the main function
+
+display_error:
+    mov eax, error_msg ; Load error message address
+    call print_string ; Display error message
+    call print_nl ; Print newline after error message
+    jmp exit_programme ; Jump to program exit
+
+range_error:
+    mov eax, range_error_msg ; Load range error message address
+    call print_string ; Display range error message
+    call print_nl ; Print newline after range error
+
+exit_programme:
+    popa ; Restore states of the registers
+    mov eax, 0 ; Signal successful completion
+    ret ; Return from the function
-- 
GitLab