[CMSC 313 Home] | [Syllabus] | [Homework] | [Projects] | [Lecture Notes] | [Printable all notes] | [Files] | [NASM resource] |
The project is to be submitted on linux.gl.umbc.edu as submit cs313 proj1 convert.asm submit cs313 proj2 list_64.asm submit cs313 proj3 plot.asm submit cs313 proj4 proj4.vhdl or submit cs313 proj4 proj4.v submit cs313 proj5 proj5.vhdl or submit cs313 proj5 proj5.v To see what is submitted submitls cs313 proj1 To delete a file that was submitted submitrm cs313 proj1 convert.asm
From anywhere you can reach the internet:
ssh your-username@linux.gl.umbc.edu # or use putty, etc.
your-password
mkdir cs313 # or whatever directory name you want, only once
cd cs313 # every time you log in for CMSC 313
# Get some sample files. (some not needed until later)
cp /afs/umbc.edu/users/s/q/squire/pub/download/hello.asm .
cp /afs/umbc.edu/users/s/q/squire/pub/download/intarith_64.asm .
cp /afs/umbc.edu/users/s/q/squire/pub/download/xor.circ .
# be sure to type the final space dot
# you can type in the command lines or get these Makefile's
cp /afs/umbc.edu/users/s/q/squire/pub/download/Makefile_nasm .
# test compile hello.asm
nasm -f elf64 hello.asm # or just make -f Makefile_nasm
gcc -m64 -o hello hello.o
./hello > hello.out
cat hello.out
ls -ltr # see files you have
Or type
make -f Makefile_nasm
ls -ltr
If this did not work, see Help Desk, T.A. or instructor
Write and submit a NASM assembly language program
"convert.asm" that implements the number conversions
that you did for Homework 1. The file "intarith_64.asm"
might be helpful.
You start with two constants in the .data section
dec1: db '1','2','4','.','3','7','5',0
bin1: dq 01010110110101B ; 10101101.10101 note where binary point should be
You convert dec1 to a string of characters that is
the binary representation of 124.3750 with a binary point
and three bits to the right of the binary point.
Print your characters (string) with printf or a kernel call.
You convert bin1 to a string of characters that is
the decimal representation of 10101101.10101.
Print your characters (string) with printf or a kernel call.
You may use any method of your choice, and you may print results
as four numbers: '1','2','4' as 1's and 0's, binary.
'.','3','7','5' as '.' 1's and 0's binary.
010101101 as a decimal number, integer
.10101 as a decimal number, .dddd decimal fraction.
submit your file, when it is working correctly,
submit cs313 proj1 convert.asm
Your file must assemble with no errors and execute
with the commands:
nasm -f elf64 convert.asm
gcc -m64 -o convert convert.o
./convert # ./ needed if '.' not first in PATH
Then submit cs313 proj1 convert.asm
Note: '1' is an ASCII character. Subtract 48 from an ASCII
character to get a binary number. Add 48 to a binary
number in the range 0 to 9 to get the ASCII character
'0' to '9'.
'1','2','4' is 1*100 + 2*20 + 4 = 124, binary in a register.
See horner_64.asm for sample loops.
and loopint_64.asm another sample.
You do not have to use loops, you can solve just specific problem.
It is OK to process and print one character or digit at a time.
A snippet of sample code for printing in Nasm:
dec1: db '1','2','4','.','3','7','5', 0
fmt_char: db "%c",0 ; no '\n' thus no 10
fmt_dig: db "%1ld",0 ; print just one digit, e.g. 0 or 1
fmt_end: db 10, 0 ; just end line
mov rdi,fmt_char ; print a single character
mov al, [dec1] ; byte into bottom of rax
mov rsi, rax ; must go 64-bit to 64-bit
mov rax, 0 ; no float
call printf
mov rdi,fmt_dig ; print a single character as digit
mov rax, 0 ; be safe, zero all rax
mov al, [dec1+1] ; next byte into bottom of rax
sub rax, 48 ; change character digit to number
; imul rax, 10 ; '2' is 20 need to add up 1*100+2*10+4
mov rsi, rax ; must go 64-bit to 64-bit
mov rax, 0 ; no float
call printf
mov rdi,fmt_end ; print end of line
mov rax, 0 ; no float
call printf
Note: and rax,1 ; print with %1ld, prints bottom bit as 0 or 1
; shr rax to get the bit you want
Hint, C code, for converting .375 to .011
frac_bin.c
frac_bin.out
Beware rounding when storing double as integer.
May need fld, fld, compp as in ifflt_64.asm
Partial credit: 25% for decimal integer to binary
25% for decimal fraction to binary
25% for binary integer to decimal
25% for binary fraction to decimal
Zero points if your convert.asm does not compile,
if your convert.asm just prints the answers without
doing the conversion.
if two or more convert.asm are copied
Write and submit NASM assembly language functions
that implement the given "C" functions in list_64.c
The main program test_list_64.c
that does not know how the functions are implemented.
Much less work than it may appear, push and pop, front and back very similar.
The test program is test_list_64.c
The .h file with function prototypes is list_64.h
Your correct output should be test_list_64.outc
Note: There is zero credit when list_64.asm does not compile without errors.
There is 25% credit when 'clear' 'push_back' and 'print' work.
There is 50% credit when three 'push_back' also work.
There is 75% credit when two lists and 'push_front' also work.
There is 90% credit when 'pop_front' and 'pop_back' also work.
There is 100% credit when all of test_list works.
Your file must assemble with no errors and execute on linux.gl.umbc.edu
with the commands:
A possible starter file list_part_64.asm for list_64.c
cp list_part_64.asm list_64.asm then remove "_part" and fix comments
nasm -g -f elf64 -l list_64.lst list_64.asm
gcc -g3 -m64 -o test_list_64 test_list_64.c list_64.o
./test_list_64 > test_list_64.out
cat test_list_64.out
Then submit cs313 proj2 list_64.asm
For debugging due to segfault:
gdb test_list_64
break main
run
step
step keep stepping until segfault, thus see where you have a bug
For anyone who has not had linked list:
More sample code for moving characters, bytes,
test_alist_64.asm
Use the test program: test_list_64.c
// test_list_64.c simple use of "list" functions
// function prototypes for functions to be written in assembly language:
#include "list_64.h"
#include <stdio.h> // for debug
// The assembly language program must be in a single file list_64.asm
// The following sequence of commands must run correctly on linux.gl
// nasm -g -f elf64 -l list_64.lst list_64.asm
// gcc -g3 -m64 -o test_list_64 test_list_64.c list_64.o
// ./test_list_64 test_list_64.out
// cat test_list_64.out
// partial credit based on how far it executes before segfault or error
int main()
{
long int L1[2]; // allocate space for two pointers for list L1
long int L2[2]; // allocate space for two pointers for list L2
char hello[]="Hello"; // just a string for use later
printf("test_list_64.c running, testing list_64.asm \n");
L1[0] = 5;
L1[1] = 6;
clear(L1); // address of L1, space for two pointers
printf("clear set L1[0]=%ld, L1[1]=%ld \n", L1[0], L1[1]);
print(L1); // should print blank line
push_back(L1,"front");
printf("did push_back L1[0]=%ld, L1[1]=%ld \n", L1[0], L1[1]); // debug
print(L1); // 25% of project credit
printf("back from print, front \n"); // debug
push_back(L1,"middle");
printf("did 2nd push_back L1[0]=%ld, L1[1]=%ld \n", L1[0], L1[1]); // debug
print(L1);
printf("back from print, front,middle \n"); // debug
push_back(L1,"last");
printf("did 3rd push_back L1[0]=%ld, L1[1]=%ld \n", L1[0], L1[1]); // debug
print(L1); // 50% of project credit
clear(L2); // another list, its own two pointers
printf("clear L2 L2[0]=%ld, L2[1]=%ld \n", L2[0], L2[1]);
push_front(L2, "end");
printf("did push_front L2[0]=%ld, L2[1]=%ld \n", L2[0], L2[1]); // debug
print(L2);
push_front(L2, "center");
printf("did push_front center L2[0]=%ld, L2[1]=%ld \n", L2[0], L2[1]); // debug
push_front(L2, "start");
printf("did push_front start L2[0]=%ld, L2[1]=%ld \n", L2[0], L2[1]); // debug
print(L2); // 75% of project credit
printf("do pop_front(L1) \n");
pop_front(L1); // removes first item on list L1
printf("did pop_front L1[0]=%ld, L1[1]=%ld \n", L1[0], L1[1]); // debug
printf("do pop_back(L1) \n");
pop_back(L1); // removes last item on list
printf("did pop_back L1[0]=%ld, L1[1]=%ld \n", L1[0], L1[1]); // debug
printf("do print(L1) \n");
print(L1); // 90% of project credit
push_front(L1, hello);
hello[0]='g';
hello[1]='o';
hello[2]='o';
hello[3]='d';
hello[4]=' ';
push_back(L2, hello);
print(L1);
print(L2); // 100% of project credit
return 0;
}
// Output of this program is:
/*
test_list_64.c running, testing list_64.asm
clear set L1[0]=0, L1[1]=0
did push_back L1[0]=1, L1[1]=1
front
back from print, front
did 2nd push_back L1[0]=1, L1[1]=4
front
middle
back from print, front,middle
did 3rd push_back L1[0]=1, L1[1]=7
front
middle
last
clear L2 L2[0]=0, L2[1]=0
did push_front L2[0]=10, L2[1]=10
end
did push_front center L2[0]=13, L2[1]=10
did push_front start L2[0]=16, L2[1]=10
start
center
end
do pop_front(L1)
did pop_front L1[0]=4, L1[1]=7
do pop_back(L1)
did pop_back L1[0]=4, L1[1]=4
do print(L1)
middle
Hello
middle
start
center
end
good
*/
Your project is to convert list_64.c to list_64.asm
// list_64.c these are the functions to implement list_64.asm
// a doubly linked list of strings
#include <stdio.h> // extern printf in list.asm
static char heap[20000]; // space to store strings, do not reuse or free
// could be gigabytes
static char *hp = heap; // pointer to next available heap space
static long int list[1000]; // space to store list block (2 index and pointer)
// could be millions
static long int lp=1; // index to next available list space
static char *q; // a variable pointer
static long int i; // a variable index
// +-----------------+ +-----------------+ +-----------------+
// L[0]-> | index to next----->| index to next----->| 0 means last |
// | 0 means first |<-----index to prev |<-----index to prev |<-L[1]
// | ptr to heap str | | ptr to heap str | | ptr to heap str |
// +-----------------+ +-----------------+ +-----------------+
// The pointers to heap strings are character pointers to terminated strings.
// The "index" values could be pointers rather than indices.
void clear(long int *L) // initialize front and back pointers to zero
{
L[0]=0; // later, will be index into "front" of list
L[1]=0; // later, will be index into "back" of list
} // end clear
void print(long int *L)
{
i=L[0]; // index into front of 'list'
while(i) // keep looping until i==0, meaning end of list
{
q=(char *)list[i+2]; // get this list items pointer to string
printf("%s\n",q); // print this list item's string
i=list[i]; // move to next list item
}
printf("\n"); // blank line after items
} // end print
void push_front(long int *L, char *s)
{
if(L[0]==0) // list is empty
{
L[0]=lp; // front index
L[1]=lp; // back index
list[lp]=0; // new next index is end
list[lp+1]=0; // new prev index is end
}
else
{
i=L[0]; // save index to old front
L[0]=lp; // new front index
list[lp]=i; // new next index is old front
list[lp+1]=0; // new prev index is end
// old front next is unchanged
list[i+1]=lp; // old front prev is now new front
}
list[lp+2]=(long int)hp; // list pointer to string on heap
lp=lp+3; // update to next free space in list
q=s;
while(*q) // copy string s to heap
{
*hp=*q; // could be written *hp++=*q++;
hp++;
q++;
}
*hp=0; // save the final null and update heap pointer
hp++; // we should do range checking, but won't
} // end push_front
void push_back(long int *L, char *s)
{
if(L[0]==0) // list is empty
{
L[0]=lp; // front index
L[1]=lp; // back index
list[lp]=0; // new next index is end
list[lp+1]=0; // new prev index is end
}
else
{
i=L[1]; // save index to old back
L[1]=lp; // new back index
list[lp]=0; // new next is end
list[lp+1]=i; // new prev index is old back
list[i]=lp; // old back next is new back
// old back prev is unchanged
}
list[lp+2]=(long int)hp; // list pointer to string on heap
lp=lp+3; // update to next free space in list
q=s;
while(*q) // copy string s to heap
{
*hp=*q; // could be written *hp++=*q++;
hp++;
q++;
}
*hp=0; // save the final null and update heap pointer
hp++; // we should do range checking, but won't
} // end push_back
void pop_front(long int *L)
{
if(L[0]==0) return; // list is already empty
if(L[1]==L[0]) // only one item on list
{
L[0]=0; // delete one item, same as clear
L[1]=0;
return;
}
i=L[0]; // get index of old front
i=list[i]; // get next from old front
L[0]=i; // L[0] is new front
// new next is unchanged
list[i+1]=0; // new prev is now end
} // end pop_front
void pop_back(long int *L)
{
if(L[1]==0) return; // list already empty
if(L[1]==L[0]) // only one item on list
{
L[0]=0; // delete one item, same as clear
L[1]=0;
return;
}
i=L[1]; // get index of back
i=list[i+1]; // get index of prev to back
L[1]=i; // L[1] is new back
list[i]=0; // new next is now end
// new prev is unchanged
} // end pop_back
// end list_64.c file
You should use the starter file: list_part_64.asm
This has all the functions with just printout, you implement
the "C" procedures list_64.c then remove the extra printout
in your final version you submit.
; list_part_64.asm a partial coding of list_64.c, rename list_64.asm
; (list_64.c included as comments)
; remove debug printout in final submitted version
; Just Part! This enters, prints parameters, the exits
; standard function entry and exit used, not optimized
; list_64.c these are the functions to implement in list_64.asm
; #include <stdio.h> ; extern printf in list_64.asm
extern printf
; static char heap[20000] ; space to store strings, do not reuse or free
; static char *hp = heap; ; pointer to next available heap space
; static long int list[1000]; ; space to store list block (2 index+ pointer)
; static long int lp=1; ; index to next available list space
; static char *q; ; a variable pointer
; static long int i; ; a variable index
section .bss
heap: resb 20000 ; could be gigabytes
list: resq 1000 ; could be millions
q: resq 1 ; may be just in rsi
i: resq 1 ; may be just in rdi
section .data
hp: dq heap ; [hp] is pointer to next free heap
lp: dq 1 ; index of next available list item
fmt1: db "%s",10,0 ; "%s\n" for printf
fmt2: db 10,0 ; "\n"
fmt_clear: db "in clear, address of callers L is %lX", 10, 0
fmt_print: db "in print, address of callers L is %lX", 10, 0
fmt_push_front: db "in push_front, address of callers L is %lX *s is %s", 10, 0
fmt_push_back: db "in push_back, address of callers L is %lX *s is %s", 10, 0
fmt_pop_front: db "in pop_front, address of callers L is %lX", 10, 0
fmt_pop_back: db "in pop_back, address of callers L is %lX", 10, 0
; +-----------------+ +-----------------+ +-----------------+
; L[0]-> | index to next----->| index to next----->| 0 |
; | 0 |<-----index to prev |<-----index to prev |<-L[1]
; | ptr to heap str | | ptr to heap str | | ptr to heap str |
; +-----------------+ +-----------------+ +-----------------+
; The pointers to heap strings are character pointers to terminated strings.
; The "index" values could be pointers rather than indices.
; void clear(int *L) ; initialize front and back pointers to zero
; {
section .text
global clear
clear:
push rbp ; save rbp, no registers need saving
; L[0]=0; ; later, will be index into "front" of list
; L[1]=0; ; later, will be index into "back" of list
; address of callers L is in rdi
mov rax,0
mov [rdi],rax ; L[0]=0
mov [rdi+8],rax ; L[1]=0
mov rax,rdi ; address of L, print it
mov rdi,fmt_clear
mov rsi,rax
mov rax,0
call printf
pop rbp
ret ; return
; } // end clear
; void print(int *L)
; {
global print
print:
push rbp ; save rbp
push rbx ; save registers
push rdi
push rsi
; i=L[0]; ; index into front of 'list'
; while(i) ; keep looping until i==0, meaning end of list
; {
; q=(char *)list[i+2]; ; get this list items pointer to string
; printf("%s\n",q); ; print this list item's string
; i=list[i]; ; move to next list item
; }
; printf("\n"); ; blank line after items
mov rax,rdi ; address of L, print it
mov rdi,fmt_print
mov rsi,rax
mov rax, 0
call printf
pop rsi ; restore registers
pop rdi ; in reverse order
pop rbx
pop rbp
ret ; return
; } // end print
; void push_front(int *L, char *s)
; {
global push_front
push_front:
push rbp ; save rbp
push rbx ; save registers
push rdi
push rsi
; if(L[0]==0) ; list is empty
; {
; L[0]=lp; ; front index
; L[1]=lp; ; back index
; list[lp]=0; ; new next index is end
; }
; else
; {
; i=L[0]; ; save index to old front
; L[0]=lp; ; new front index
; list[lp]=i; ; new next index is old front
; list[lp+1]=0; ; new prev index is end
; ; old front next is unchanged
; list[i+1]=lp; ; old front prev is now new front
; }
; list[lp+2]=(int)hp; ; list pointer to string on heap
; lp=lp+3; ; update to next free space in list
; q=s;
; while(*q) ; copy string s to heap
; {
; *hp=*q; ; could be written *hp++=*q++;
; hp++;
; q++;
; }
; *hp=0; ; save the final null and update heap pointer
; hp++; ; we should do range checking, but won't
mov rax,rdi ; address of L, print it
mov rbx,rsi ; address of string, print it
mov rdi,fmt_push_front
mov rsi,rax
mov rdx,rbx
mov rax, 0
call printf
pop rsi ; restore registers
pop rdi ; in reverse order
pop rbx
pop rbp
ret ; return
; } // end push_front
; void push_back(long int *L, char *s)
; {
global push_back
push_back:
push rbp ; save rbp
push rbx ; save registers
push rdi
push rsi
; if(L[0]==0) ; list is empty
mov rax,[rdi] ; L[0] in rax
cmp rax,0 ; test ==0
jne falseb ; jump to false part
; {
; L[0]=lp; ; front index
; L[1]=lp; ; back index
; list[lp]=0; ; new next index is end
; list[lp+1]=0; ; new prev index is end
; }
jmp endifb
falseb:
; else
; {
; i=L[1]; ; save index to old back
; L[1]=lp; ; new back index
; list[lp]=0; ; new next is end
; list[lp+1]=i; ; new prev index is old back
; list[i]=lp; ; old back next is new back
; ; old back prev is unchanged
; }
endifb:
; list[lp+2]=(long int)hp; ; list pointer to string on heap
; lp=lp+3; ; update to next free space in list
; q=s; ; s is in rsi, do not need q
; while(*q) ; copy string s to heap
; {
; *hp=*q; ; could be written *hp++=*q++;
; hp++;
; q++;
; }
pb3lab: mov rcx,[hp]
mov rdx,0 ; clear before loading byte
mov dl,[rsi] ; byte in rdx
cmp dl,0
je pb4lab
mov [rcx],dl
inc rcx
mov [hp],rcx
inc rsi
jmp pb3lab
; *hp=0; ; save the final null and update heap pointer
; hp++; ; we should do range checking, but won't
pb4lab:
mov rdx,0
mov [rcx],dl
inc rcx
mov [hp],rcx
mov rax,rdi ; address of L, print it
mov rbx,rsi ; address of string, print it
mov rdi,fmt_push_back
mov rsi,rax
mov rdx,rbx
mov rax, 0
call printf
pop rsi ; restore registers
pop rdi ; in reverse order
pop rbx
pop rbp
ret ; return
; } // end push_back
; void pop_front(int *L)
; {
global pop_front
pop_front:
push rbp ; save rbp
push rbx ; save registers
push rdi
push rsi
; if(L[0]==0) return; ; list is already empty
; if(L[1]==L[0]) ; only one item on list
; {
; L[0]=0; ; delete one item, same as clear
; L[1]=0;
; return;
; }
; i=L[0]; ; get index of old front
; i=list[i]; ; get next from old front
; L[0]=i; ; L[0] is new front
; ; new next is unchanged
; list[i+1]=0; ; new prev is now end
mov rax,rdi ; address of L, print it
mov rdi,fmt_pop_front
mov rsi,rax
mov rax, 0
call printf
pop rsi ; restore registers
pop rdi ; in reverse order
pop rbx
pop rbp
ret ; return
; } // end pop_front
; void pop_back(int *L)
; {
global pop_back
pop_back:
push rbp ; save rbp
push rbx ; save registers
push rdi
push rsi
; if(L[1]==0) return; ; list already empty
; if(L[1]==L[0]) ; only one item on list
; {
; L[0]=0; ; delete one item, same as clear
; L[1]=0;
; return;
; }
; i=L[1]; ; get index of back
; i=list[i+1]; ; get index of prev to back
; L[1]=i; ; L[1] is new back
; list[i]=0; ; new next is now end
; ; new prev is unchanged
mov rax,rdi ; address of L, print it
mov rdi,fmt_pop_back
mov rsi,rax
mov rax, 0
call printf
pop rsi ; restore registers
pop rdi ; in reverse order
pop rbx
pop rbp
ret ; return
; } // end pop_back
; end list_part_64.asm file
Output using list_part_64.asm is
test_list_64.c running, testing list_64.asm
in clear, address of callers L is 7FFF2C8E5980
clear set L1[0]=0, L1[1]=0
in print, address of callers L is 7FFF2C8E5980
in push_back, address of callers L is 7FFF2C8E5980 *s is
did push_back L1[0]=0, L1[1]=0
in print, address of callers L is 7FFF2C8E5980
back from print, front
in push_back, address of callers L is 7FFF2C8E5980 *s is
did 2nd push_back L1[0]=0, L1[1]=0
in print, address of callers L is 7FFF2C8E5980
back from print, front,middle
in push_back, address of callers L is 7FFF2C8E5980 *s is
did 3rd push_back L1[0]=0, L1[1]=0
in print, address of callers L is 7FFF2C8E5980
in clear, address of callers L is 7FFF2C8E5970
clear L2 L2[0]=0, L2[1]=0
in push_front, address of callers L is 7FFF2C8E5970 *s is end
did push_front L2[0]=0, L2[1]=0
in print, address of callers L is 7FFF2C8E5970
in push_front, address of callers L is 7FFF2C8E5970 *s is center
did push_front center L2[0]=0, L2[1]=0
in push_front, address of callers L is 7FFF2C8E5970 *s is start
did push_front start L2[0]=0, L2[1]=0
in print, address of callers L is 7FFF2C8E5970
do pop_front(L1)
in pop_front, address of callers L is 7FFF2C8E5980
did pop_front L1[0]=0, L1[1]=0
do pop_back(L1)
in pop_back, address of callers L is 7FFF2C8E5980
did pop_back L1[0]=0, L1[1]=0
do print(L1)
in print, address of callers L is 7FFF2C8E5980
in push_front, address of callers L is 7FFF2C8E5980 *s is Hello
in push_back, address of callers L is 7FFF2C8E5970 *s is
in print, address of callers L is 7FFF2C8E5980
in print, address of callers L is 7FFF2C8E5970
All referenced files may be copied to your directory using:
Replace xxx.x with the file you want.
cp /afs/umbc.edu/users/s/q/squire/pub/download/xxx.x .
You are to write a program that does not use "C" functions or libraries.
This project is based on lecture 8.
You may use system calls or BIOS calls from Lecture 9 to implement the program.
See hellos_64.asm for compiling, _start
nasm -f elf64 plot.asm
ld -o plot plot.o
./plot
You only need to print one character at a time, rdx, 1 in syscall.
Print 10, '\n' at end of each line.
Or, add one column filled with 10, and print lines=rows.
Your program is to make a simple character plot of sin(x)
for x from -Pi to Pi, -3.14159 to 3.14159 in 41 steps, dx = 0.15708
Use 21 rows, middle row for sin(0.0) = 0,
top row for sin(Pi/2) = 1.0, bottom row for sin(-Pi/2) = -1
For each column plotting an '*' at row k = int(20.0 - (y+1)*10.0)
A very small version of the plot would look like:
* 9 columns, 7 rows
* *
* * *
* *
*
Compute sin(x) in your program y = sin(x) =
x - x^3/3! + x5^/5! - x^7/7!
OK to use code from horner_64.asm float
af: dq 0.0, 1.0, 0.0, -0.166667, 0.0, 0.00833, 0.0, -0.000198
N: dq 7
XF: x=0, x=x+dx dx = 0.15708
This computes YF = sin(XF)
mov rcx,[N] ; loop iteration count initialization, n
fld qword [af+8*rcx]; accumulate value here, get coefficient a_n
h5loop: fmul qword [XF] ; * XF
fadd qword [af+8*rcx-8] ; + aa_n-i
loop h5loop ; decrement rcx, jump on non zero
fstp qword [Y] ; store Y
Then compute kf = 20.0 - (Y+1.0)*10.0 floating point
Then store k as integer: fistp qword [k]
Then compute double subscript, integer, k*ncol+j in rax
Then store star:
mov bl, [star]
mov [a2+rax], bl
Note: For printing mov rsi, rax // syscall (rcx for int)
add rsi, a2 // not [a2+rax] need address
If it runs to your satisfaction,
Then submit cs313 proj3 plot.asm
The program in "C" is
See plot_64.c for possible method
See plot_64.outc "C" output
See plot_chk.out Nasm output
See horner_64.asm for computing sin(x)
// plot_64.c simple plot of sin(x)
#include <stdio.h>>
#define ncol 41
#define nrow 21
int main(int argc, char *srgv[])
{
char points[nrow][ncol]; // char == byte
char point = '*';
char space = ' ';
long int i, j, k, rcx;
double af[] = {0.0, 1.0, 0.0, -0.166667,
0.0, 0.00833, 0.0, -0.000198};
long int N = 7;
double x, y;
double dx = 0.15708; // 6.2832/40.0
// clear points to space ' '
for(i=0; i<nrow; i++)
for(j=0; j<ncol; j++)
points[i][j] = space;
// compute points
x = -3.14159;
for(j=0; j<ncol; j++)
{
y = af[N]*x + af[N-1]; // horners h5loop
for(rcx=N-2; rcx>=0; rcx--) y = y*x + af[rcx];
k = (20.0 - (y+1.0)*10.0); // scale 1.0 to -1.0, 0 to 20 integer
points[k][j] = point;
x = x + dx;
}
// print points
for(i=0; i<nrow; i++)
{
for(j=0; j<ncol; j++)
printf("%c", points[i][j]);
printf("\n");
}
return 0;
} // end plot_64.c
Nasm code for loops to clear and print array of characters
array2_64.asm sample code
array2_64.out output
snippet of code, double loop, to clear array
(ultra conservative, keeping i and j in memory)
These 3 lines of "C" code become many lines of assembly
// clear points to space ' '
for(i=0; i<nrow; i++)
for(j=0; j<ncol; j++)
points[i][j] = space;
section .bss ; ncol=7, nrow=5 for demo
a2: resb 21*41 ; two dimensional array of bytes
i: resq 1 ; row subscript
j: resq 1 ; col subscript
k: resq 1 ; row subscript computed
SECTION .text ; Code section. just snippet
; clear a2 to space
mov rax,0 ; i=0 for(i=0;
mov [i],rax
loopi:
mov rax,[i] ; reload i, rax may be used
mov rbx,0 ; j=0 for(j=0;
mov [j],rbx
loopj:
mov rax,[i] ; reload i, rax may be used
mov rbx,[j] ; reload j, rbx may be used
imul rax,[ncol] ; i*ncol
add rax, rbx ; i*ncol + j
mov dl, [spc] ; need just character, byte
mov [a2+rax],dl ; store space
mov rbx,[j]
inc rbx ; j++
mov [j],rbx
cmp rbx,[ncol] ; j<ncol
jne loopj
mov rax,[i]
inc rax ; i++
mov [i],rax
cmp rax,[nrow] ; i<ncol
jne loopi
; end clear a2 to space
; j = 0;
; xf = X0;
From horner_64.asm use
sin: mov rcx,[N] ; loop iteration count initialization, n
fld qword [af+8*rcx]; accumulate value here, get coefficient a_n
h5loop: fmul qword [XF] ; * XF
fadd qword [af+8*rcx-8] ; + aa_n-i
loop h5loop ; decrement rcx, jump on non zero
fstp qword [Y] ; store Y
; k = 20.0 *(Y+1.0)*(-10.0) fistp qword [k]
; rax gets k * ncol + j
; put "*" in dl, then dl into [a2+rax]
; XF = XF + DX0;
; j = j+1;
; if(j != ncol) go to sin
; copy clear a2 to space
; in jloop renamed, use syscall print from hellos_64.asm
; add rax,a2 replaces dl stuff
; mov rsi, rax (moved up) replaces mov rsi, msg
; replace any len with 1
; after jloop insert line feed lf: db 10
; mov rsi, lf in lpace of mov rsi, rax
; use exit code from hellos_64.asm
; no push or pop rbx
in .data
af: dq 0.0, 1.0, 0.0, -0.166667; coefficients of polynomial, a_0 first
dq 0.0, 0.00833, 0.0, -0.000198
XF: dq 0.0 ; computed
Y: dq 0.0 ; computed
N: dq 7 ; power of polynomial
X0: dq -3.14159 ; start XF
DX0: dq 0.15708 ; increment for XF ncol-1 times
one: dq 1.0
nten: dq -10.0
twenty dq 20.0
Your plot.asm can not use printf or any "C" functions.
Thus you use global _start and _start: in place of
global main and main:
; compile using nasm -g -f elf64 plot.asm
; ld -o plot plot.o # not gcc
; ./plot > plot.out
; cat plot.out
Use VHDL or Verilog: For Vhdl: Use proj4.vhdl as the start of project 4. Everything has been provided to build and test a 4-bit times 4-bit unsigned parallel multiply. In order to have less VHDL, a "madd4" entity was created. The multiplier can now be built from exactly four of the "madd4" entities. (Slightly different from multiplier used in the lecture.) The first "madd4" is in the file. You must code the three remaining "madd4" and code the "dot" merge of "cout" with the top three bits of the "sum", and the product bits "p".Notes: Each box is a madd4 entity. The boxes should be labeled a0:, a1:, a2: and a3:. The cout signals are named c(0), c(1), c(2) and c(3). The sum signals are named s0, s1, s2, p(6 downto 3). The dot where three wires join the cout wire is coded in VHDL as s0s <= c(0) & s0(3 downto 1); The s0s 4-bit signal goes into the madd4 'b' input. The first 'b' input must be four zero bits, signal zero4. The low order product bit, p(0) is the bottom bit of s0 and is coded in VHDL as p(0) <= s0(0); For Verilog: Use proj4.v as the start of project 4. This is a modification of mul4.v Fill in module madd4 using four madd modules. Then instantiate four madd4 to build the circuit. Your output should have correct 1 or 0 in place of "z" proj4_v.out proj4_v.chk Other sample Verilog files add4.v mul4.v
First: You must have an account on a GL machine. Every student
and faculty should have this.
Either log in directly to linux.gl.umbc.edu or
Use ssh linux.gl.umbc.edu
Be in your cs313 directory, else files must be changed.
You can copy many sample files to your working directory using:
cp /afs/umbc.edu/users/s/q/squire/pub/download/cs313.tar .
There are many files available.
Next: Follow instructions exactly or you figure out a variation.
1) Get this tar file into your home directory (on /afs i.e.
available on all GL machines.)
cs313.tar and then type commands:
cp /afs/umbc.edu/users/s/q/squire/pub/download/cs313.tar .
tar -xvf cs313.tar
cd vhdl
fix cds.lib to have correct path
source vhdl_cshrc
make
more add32_test.out
make clean # saves a lot of disk quota
If verilog does not run, use command:
source /afs/umbc.edu/software/cadence/etc/setup_2008/cshrc.cadence
Then do your own thing with Makefile for other VHDL files
You are on your own to write VHDL or Verilog and modify the Makefile.
Remember each time you log on:
cd vhdl
source vhdl_cshrc
make # or do your own thing.
Now work project 4:
Run the following commands:
cp /afs/umbc.edu/users/s/q/squire/pub/download/proj4.vhdl .
cp /afs/umbc.edu/users/s/q/squire/pub/download/proj4.run .
cp /afs/umbc.edu/users/s/q/squire/pub/download/proj4.chk .
cp /afs/umbc.edu/users/s/q/squire/pub/download/proj4.make .
You should get some results from the command
make -f proj4.make
or verilog -q -l proj4_v.out proj4.v
Lots of "U" until you insert the VHDL for the project.
Now, work the project.
You do the submit, submit cs313 proj4 proj4.vhdl or
submit cs313 proj4 proj4.v
check your products by hand or computer
Finish up the design and finish up the implementation of a six bit spin lock. You are given a starter VHDL file proj5.vhdl Or, use the given starter Verilog file proj5.v The spin lock is given byUse names A, B, C, D, E, F for the spin lock, there is debug print in proj5.vhdl and proj5.v for testing. Initialize all D flip flops to '0' except set A to '1'. Be sure to compute "activate" along with the Ain, Bin, etc. The test input has the name "rcvr" and has 10 entries. The code to be detected is 6 bits in the middle. The entity dff1 in VHDL, module dff6 in verilog, is used by the spin lock is ready to use in proj5.vhdl. The circuit symbol is:
The module dff6 that is used by the spin lock is ready to use in proj5.v. similar circuit symbol. Your project is to finish the VHDL or verilog code for the spin lock. Look for "???" See lecture notes Lect 23 for method of converting a sequential circuit to digital logic. The lecture notes have legal VHDL statements, e.g Ain <= ... ; The Verilog uses Ain = ...; Code the digital logic in VHDL and add the VHDL statements into proj5.vhdl Copy files into your vhdl directory with the following commands: cp /afs/umbc.edu/users/s/q/squire/pub/download/proj5.vhdl . cp /afs/umbc.edu/users/s/q/squire/pub/download/proj5.run . cp /afs/umbc.edu/users/s/q/squire/pub/download/proj5_vhdl.out . cp /afs/umbc.edu/users/s/q/squire/pub/download/proj5.make . You should get some results from the command make -f proj5.make proj5_vhdl.chk . Lots of "U" until you insert the VHDL for the project. For Verilog Copy files into your vhdl directory with the following commands: cp /afs/umbc.edu/users/s/q/squire/pub/download/proj5.v . Run with verilog -q -l proj5_v.out proj5.v output before adding project proj5_v.out . Now work project 5. Then submit cs313 proj5 proj5.vhdl or submit cs313 proj5 proj5.v proj5_v.chk .
Note: push_front in list_part_64.asm updated
Note: more added to proj4.v
Note: more added to proj3.v
Last updated 5/5/2015