├── README.md ├── extract.jsh ├── files ├── assembly.rkt ├── assembly.m ├── assembly.v └── assembly.c ├── .gitignore └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # Copilot Learning Materials 2 | 3 | My type-ups for copilot to learn from. I'm uploading these text documents because I felt a great pain when writing them down and I wish this can help people. Please _don't_ use them for unethical purposes. 4 | 5 | ## How to generate your own "copilot learning materials"? 6 | 7 | Use Java >= 11, run 8 | 9 | ``` 10 | jshell extract.jsh 11 | ``` 12 | -------------------------------------------------------------------------------- /extract.jsh: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | import java.nio.file.*; 3 | import java.nio.file.attribute.BasicFileAttributes; 4 | import java.util.*; 5 | import java.util.function.Function; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.Stream; 8 | var exts = Stream.of("rkt", "md", "tex", "m", "v", "c").collect(Collectors.toMap(Function.identity(), o -> new ArrayList())); 9 | var target = Paths.get("files"); 10 | if (Files.notExists(target)) Files.createDirectory(target); 11 | Files.walkFileTree(target, new SimpleFileVisitor<>() { 12 | @Override 13 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { 14 | if (attrs.isRegularFile()) Files.deleteIfExists(file); 15 | return FileVisitResult.CONTINUE; 16 | } 17 | }); 18 | Files.walkFileTree(Paths.get("."), new SimpleFileVisitor<>() { 19 | @Override 20 | public FileVisitResult visitFile(Path p, BasicFileAttributes attrs) throws IOException { 21 | var fileName = p.toString(); 22 | var ext = fileName.substring(fileName.lastIndexOf('.') + 1); 23 | if (!exts.containsKey(ext)) return FileVisitResult.CONTINUE; 24 | var content = Files.readString(p) 25 | .replaceAll("yqz5714", "") 26 | .replaceAll("(Stat|Math|Cmpsc|Cmpen)\\d+", "") 27 | .replaceAll("\r", "") 28 | .replaceAll("Tesla[()\\w ]+Zhang", "") 29 | .replaceAll("Zihui[()\\w ]+Xie", "") 30 | .replaceAll("Yuanxiang[()\\w ]+Wang", "") 31 | .replaceAll("Yinsen[()\\w ]+Zhang", ""); 32 | exts.get(ext).addAll(List.of(content.split("\\R\\R+"))); 33 | return FileVisitResult.CONTINUE; 34 | } 35 | }) 36 | for (var entry : exts.entrySet()) { 37 | var ext = entry.getKey(); 38 | var v = entry.getValue(); 39 | Collections.sort(v); 40 | var content = String.join("\n\n", new HashSet<>(v)); 41 | var newPath = Paths.get("files", "assembly.%s".formatted(ext)); 42 | System.out.println(newPath + ": " + content.length()); 43 | Files.writeString(newPath, content, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE); 44 | } 45 | /exit -------------------------------------------------------------------------------- /files/assembly.rkt: -------------------------------------------------------------------------------- 1 | ;; Problem 1 2 | (define (ackermann m n) 3 | (cond 4 | [(= m 0) (+ n 1)] 5 | [(> m 0) (ackermann (- m 1) 6 | (cond 7 | [(= n 0) 1] 8 | [(> n 0) (ackermann m (- n 1))]))])) 9 | 10 | #lang racket 11 | ;; Problem 2 12 | (define (sum a b) (if (= a b) a (+ b (sum a (- b 1))))) 13 | 14 | ;; Problem 4 15 | (define zero-to-20 16 | (list 17 | '(0 zero) '(1 one) '(2 two) '(3 three) '(4 four) '(5 five) 18 | '(6 six) '(7 seven) '(8 eight) '(9 nine) '(10 ten) 19 | '(11 eleven) '(12 twelve) '(13 thirteen) '(14 fourteen) '(15 fifteen) 20 | '(16 sixteen) '(17 seventeen) '(18 eighteen) '(19 nineteen))) 21 | (define tens 22 | (list 23 | '(2 twenty) '(3 thirty) '(4 forty) '(5 fifty) 24 | '(6 sixty) '(7 seventy) '(8 eighty) '(9 ninety))) 25 | (define (to-words n) 26 | (cond 27 | ((< n 0) 'error) 28 | ((< n 20) (cdr (assoc n zero-to-20))) 29 | ((< n 100) (append (cdr (assoc (quotient n 10) tens)) 30 | (let ([q (remainder n 10)]) (if (= 0 q) '() (to-words q))))) 31 | ((< n 200) (append (to-words (quotient n 100)) '(hundred and) (to-words (remainder n 100)))) 32 | (else 'error))) 33 | 34 | ;; Problem 5 35 | (define (initialWIList xs) (for/list ([i (in-naturals 0)] [x xs]) (list x i))) 36 | (define (mergeWI x xs) (if (assoc (car x) xs) xs (append xs (list x)))) 37 | (define (mergeByWord xs) (reverse (foldr mergeWI '() xs))) 38 | (define wordMaxIndex (compose mergeByWord initialWIList)) 39 | 40 | ;; Problem 3 41 | (define (h-f n) (if (= 0 n) 1 (- n (h-m (h-f (- n 1)))))) 42 | (define (h-m n) (if (= 0 n) 0 (- n (h-f (h-m (- n 1)))))) 43 | 44 | ;; Problem 2 45 | (define (minInt_helper k x) 46 | (cond ((null? x) k) 47 | ((> k (car x)) (minInt_helper (car x) (cdr x))) 48 | (else (minInt_helper k (cdr x))))) 49 | (define (minInt x) (if (null? x) 0 (minInt_helper (car x) (cdr x)))) 50 | 51 | ;; Problem 3 52 | (define (manycall n f x) 53 | (if (<= n 1) x (manycall (- n 2) f (f (f x))))) 54 | 55 | (define (bind k v al) 56 | (append (list (list k v)) al)) 57 | (define (lookup k al) 58 | (let [(look (assoc k al))] 59 | (if look (cadr look) look))) 60 | (define al '()) 61 | 62 | ;; Problem 1 63 | (define (remove-when f x) 64 | (cond ((null? x) '()) 65 | ((f (car x)) (remove-when f (cdr x))) 66 | (else (cons (car x) (remove-when f (cdr x)))))) 67 | 68 | ;; Problem 2 69 | (define (construct_mem f) 70 | (let ((al '())) 71 | (lambda (m n) 72 | (let* [(mn (list m n)) 73 | (look (lookup mn al))] 74 | (if look 75 | (begin (display "memoization hit\n") look) 76 | (let [(feizhu (f m n))] 77 | (begin (set! al (bind mn feizhu al)) 78 | feizhu))))))) 79 | 80 | (define (ackermann_mem m n) 81 | (let* [(mn (list m n)) 82 | (look (lookup mn al))] 83 | (if look 84 | (begin (display "memoization hit\n") look) 85 | (let [(feizhu (ackermann m n))] 86 | (begin (set! al (bind mn feizhu al)) 87 | feizhu))))) 88 | 89 | #lang racket 90 | 91 | ;; Problem 4 92 | (define (reward amt) 93 | (cond 94 | [(<= amt 2000) (* 0.01 amt)] 95 | [(<= amt 4000) (+ 20 (* 0.015 (- amt 2000)))] 96 | [(<= amt 5500) (+ 20 30 (* 0.02 (- amt 4000)))] 97 | [else (+ 20 30 30 (* 0.025 (- amt 5500)))])) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Core latex/pdflatex auxiliary files: 2 | *.aux 3 | *.lof 4 | *.log 5 | *.lot 6 | *.fls 7 | *.out 8 | *.toc 9 | *.fmt 10 | *.fot 11 | *.cb 12 | *.cb2 13 | .*.lb 14 | 15 | ## Intermediate documents: 16 | *.dvi 17 | *.xdv 18 | *-converted-to.* 19 | # these rules might exclude image files for figures etc. 20 | # *.ps 21 | # *.eps 22 | # *.pdf 23 | 24 | ## Generated if empty string is given at "Please type another file name for output:" 25 | .pdf 26 | 27 | ## Bibliography auxiliary files (bibtex/biblatex/biber): 28 | *.bbl 29 | *.bcf 30 | *.blg 31 | *-blx.aux 32 | *-blx.bib 33 | *.run.xml 34 | 35 | ## Build tool auxiliary files: 36 | *.fdb_latexmk 37 | *.synctex 38 | *.synctex(busy) 39 | *.synctex.gz 40 | *.synctex.gz(busy) 41 | *.pdfsync 42 | 43 | ## Build tool directories for auxiliary files 44 | # latexrun 45 | latex.out/ 46 | 47 | ## Auxiliary and intermediate files from other packages: 48 | # algorithms 49 | *.alg 50 | *.loa 51 | 52 | # achemso 53 | acs-*.bib 54 | 55 | # amsthm 56 | *.thm 57 | 58 | # beamer 59 | *.nav 60 | *.pre 61 | *.snm 62 | *.vrb 63 | 64 | # changes 65 | *.soc 66 | 67 | # comment 68 | *.cut 69 | 70 | # cprotect 71 | *.cpt 72 | 73 | # elsarticle (documentclass of Elsevier journals) 74 | *.spl 75 | 76 | # endnotes 77 | *.ent 78 | 79 | # fixme 80 | *.lox 81 | 82 | # feynmf/feynmp 83 | *.mf 84 | *.mp 85 | *.t[1-9] 86 | *.t[1-9][0-9] 87 | *.tfm 88 | 89 | #(r)(e)ledmac/(r)(e)ledpar 90 | *.end 91 | *.?end 92 | *.[1-9] 93 | *.[1-9][0-9] 94 | *.[1-9][0-9][0-9] 95 | *.[1-9]R 96 | *.[1-9][0-9]R 97 | *.[1-9][0-9][0-9]R 98 | *.eledsec[1-9] 99 | *.eledsec[1-9]R 100 | *.eledsec[1-9][0-9] 101 | *.eledsec[1-9][0-9]R 102 | *.eledsec[1-9][0-9][0-9] 103 | *.eledsec[1-9][0-9][0-9]R 104 | 105 | # glossaries 106 | *.acn 107 | *.acr 108 | *.glg 109 | *.glo 110 | *.gls 111 | *.glsdefs 112 | *.lzo 113 | *.lzs 114 | 115 | # uncomment this for glossaries-extra (will ignore makeindex's style files!) 116 | # *.ist 117 | 118 | # gnuplottex 119 | *-gnuplottex-* 120 | 121 | # gregoriotex 122 | *.gaux 123 | *.gtex 124 | 125 | # htlatex 126 | *.4ct 127 | *.4tc 128 | *.idv 129 | *.lg 130 | *.trc 131 | *.xref 132 | 133 | # hyperref 134 | *.brf 135 | 136 | # knitr 137 | *-concordance.tex 138 | # TODO Comment the next line if you want to keep your tikz graphics files 139 | *.tikz 140 | *-tikzDictionary 141 | 142 | # listings 143 | *.lol 144 | 145 | # luatexja-ruby 146 | *.ltjruby 147 | 148 | # makeidx 149 | *.idx 150 | *.ilg 151 | *.ind 152 | 153 | # minitoc 154 | *.maf 155 | *.mlf 156 | *.mlt 157 | *.mtc[0-9]* 158 | *.slf[0-9]* 159 | *.slt[0-9]* 160 | *.stc[0-9]* 161 | 162 | # minted 163 | _minted* 164 | *.pyg 165 | 166 | # morewrites 167 | *.mw 168 | 169 | # nomencl 170 | *.nlg 171 | *.nlo 172 | *.nls 173 | 174 | # pax 175 | *.pax 176 | 177 | # pdfpcnotes 178 | *.pdfpc 179 | 180 | # sagetex 181 | *.sagetex.sage 182 | *.sagetex.py 183 | *.sagetex.scmd 184 | 185 | # scrwfile 186 | *.wrt 187 | 188 | # sympy 189 | *.sout 190 | *.sympy 191 | sympy-plots-for-*.tex/ 192 | 193 | # pdfcomment 194 | *.upa 195 | *.upb 196 | 197 | # pythontex 198 | *.pytxcode 199 | pythontex-files-*/ 200 | 201 | # tcolorbox 202 | *.listing 203 | 204 | # thmtools 205 | *.loe 206 | 207 | # TikZ & PGF 208 | *.dpth 209 | *.md5 210 | *.auxlock 211 | 212 | # todonotes 213 | *.tdo 214 | 215 | # vhistory 216 | *.hst 217 | *.ver 218 | 219 | # easy-todo 220 | *.lod 221 | 222 | # xcolor 223 | *.xcp 224 | 225 | # xmpincl 226 | *.xmpi 227 | 228 | # xindy 229 | *.xdy 230 | 231 | # xypic precompiled matrices and outlines 232 | *.xyc 233 | *.xyd 234 | 235 | # endfloat 236 | *.ttt 237 | *.fff 238 | 239 | # Latexian 240 | TSWLatexianTemp* 241 | 242 | ## Editors: 243 | # WinEdt 244 | *.bak 245 | *.sav 246 | 247 | # Texpad 248 | .texpadtmp 249 | 250 | # LyX 251 | *.lyx~ 252 | 253 | # Kile 254 | *.backup 255 | 256 | # gummi 257 | .*.swp 258 | 259 | # KBibTeX 260 | *~[0-9]* 261 | 262 | # TeXnicCenter 263 | *.tps 264 | 265 | # auto folder when using emacs and auctex 266 | ./auto/* 267 | *.el 268 | 269 | # expex forward references with \gathertags 270 | *-tags.tex 271 | 272 | # standalone packages 273 | *.sta 274 | 275 | # Makeindex log files 276 | *.lpz 277 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /files/assembly.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | function S = cspline_eval(t,y,z,x_vec) 4 | % function S = cspline_eval(t,y,z,x_vec) 5 | % compute the value of the natural cubic spline at the points x_vec when 6 | % t,y,z are given 7 | % 8 | % Example: t = [0.9,1.3,1.9,2.1]; 9 | % y = [1.3,1.5,1.85,2.1] 10 | % z = cspline(t,y) 11 | % x = [0.9:0.1:2.1] 12 | % v = cspline_eval(t,y,z,x) 13 | 14 | for j = 2:n 15 | % 2 to n column 16 | for i = j:n 17 | p = R(i, j - 1) - R(i - 1, j - 1); 18 | R(i, j) = R(i, j - 1) + p / (4^(j - 1) - 1); 19 | end 20 | end 21 | end 22 | 23 | 24 | m = length(x_vec); 25 | S = zeros(size(x_vec)); 26 | n = length(t); 27 | for j=1:m 28 | x = x_vec(j); 29 | for i=n-1:-1:1 30 | if (x-t(i)) >= 0 31 | break 32 | end 33 | end 34 | h = t(i+1)-t(i); 35 | S(j) = z(i+1)/(6*h)*(x-t(i))^3-z(i)/(6*h)*(x-t(i+1))^3 ... 36 | +(y(i+1)/h-z(i+1)*h/6)*(x-t(i)) - (y(i)/h-z(i)*h/6)*(x-t(i+1)); 37 | end 38 | 39 | 40 | function GXExp(n, d, a, b) 41 | A = sparse(zeros(n, n)); 42 | 43 | function A = divdiff(x, y) 44 | % input: x, y: the data set to be interpolated 45 | % output: A: table for Newton's divided differences. 46 | [~, n] = size(x); 47 | A = zeros(n, n); 48 | A(:, 1) = transpose(y); 49 | % k: from left to right 50 | for k = 2 : n 51 | % i: from top to bottom 52 | for i = k : n 53 | % above /: the left one subtract its upstairs 54 | above = A(i, k - 1) - A(i - 1, k - 1); 55 | % below /: the leftmost one subtract its upstairs 56 | below = x(i) - x(i - k + 1); 57 | A(i, k) = above / below; 58 | end 59 | end 60 | end 61 | 62 | 63 | function x = mysecant(f, x0, x1, tol, nmax) 64 | % input variables: 65 | % f is the function, 66 | % x0, x1 are the initial guesses, 67 | % tol is the error tolerance, 68 | % and nmax is the maximum number of iterations. 69 | % The output variable: 70 | % x is the result of the Newton iterations. 71 | x = x1; 72 | fprintf('x = %g\n', x); 73 | if nmax <= 0 74 | return; 75 | end 76 | 77 | % >> [r1, r2] = quadroots(2, 6, -3) 78 | 79 | function R = romberg(f, a, b, n) 80 | % feval(s, a): call the function `f(a)` 81 | % [a, b]: the interval of integration 82 | R = zeros(n, n); 83 | h = b - a; 84 | R(1, 1) = (feval(f, a) + feval(f, b)) * h / 2; 85 | 86 | fx = feval(f, x); 87 | if abs(fx) < tol 88 | return; 89 | end 90 | 91 | % >> [r1, r2] = smartquadroots(3, -123454321, 2) 92 | 93 | % >> roots([3, -123454321, 2]) 94 | 95 | function [x, nit] = gs(A, b, x0, tol, nmax) 96 | % tol: error tolerance 97 | % nmax: max number of iterations 98 | % A, b: the matrix system 99 | % x: solution 100 | % nit: number of iterations used 101 | x = x0; 102 | n = length(x); 103 | nit = 0; 104 | 105 | % Backward substitution 106 | x = zeros(1, n); 107 | x(n) = b(n) / A(n, n); 108 | for i = n - 1:-1:1 109 | x(i) = (b(i) - sum(A(i, i + 1:n) .* x(i + 1:n))) / A(i, i); 110 | end 111 | disp(x); 112 | end 113 | 114 | dx = fx / feval(df, x); 115 | x = mynewton(f, df, x - dx, tol, nmax - 1); 116 | end 117 | 118 | 119 | % 1.7385e-08 120 | 121 | % 4.1151e+07 122 | 123 | 124 | x = y; 125 | % fprintf("\\item $%.4f, %.4f$\n", x(1), x(2)); 126 | disp(x); 127 | nit = nit + 1; 128 | end 129 | end 130 | 131 | 132 | if fr * fa < 0 133 | r = bisection(f, a, r, tol, nmax - 1); 134 | else 135 | r = bisection(f, r, b, tol, nmax - 1); 136 | end 137 | end 138 | 139 | 140 | function ls = lspline(t, y, x) 141 | % lspline computes the linear spline 142 | % Inputs: 143 | % t: vector, contains the knots 144 | % y: vector, contains the interpolating values at knots 145 | % x: vector, contains points where the lspline function 146 | % should be evaluated and plotted 147 | % Output: 148 | % ls: vector, contains the values of lspline at points x 149 | m = length(x); 150 | n = length(t); 151 | ls = zeros(size(t)); 152 | for j = 1 : m 153 | xx = x(j); 154 | for i = n - 1 : -1 : 1 155 | if (xx - t(i)) >= 0 156 | break 157 | end 158 | end 159 | yd = y(i + 1) - y(i); 160 | td = t(i + 1) - t(i); 161 | ls(j) = yd / td * (xx - t(i)) + y(i); 162 | end 163 | end 164 | 165 | n = length(t); 166 | z = zeros(n,1); 167 | h = zeros(n-1,1); 168 | b = zeros(n-1,1); 169 | u = zeros(n,1); 170 | v = zeros(n,1); 171 | 172 | for n = 1:N 173 | k1 = feval(f, t(n), x(:, n)); 174 | k2 = feval(f, t(n) + 0.5 * h, x(:, n) + 0.5 * h * k1); 175 | k3 = feval(f, t(n) + 0.5 * h, x(:, n) + 0.5 * h * k2); 176 | k4 = feval(f, t(n) + h, x(:, n) + h * k3); 177 | x(:, n + 1) = x(:, n) + h / 6 * (k1 + 2 * (k2 + k3) + k4); 178 | end 179 | end 180 | 181 | 182 | for k = 1:2^(i - 1) 183 | R(i + 1, 1) = R(i + 1, 1) + h * feval(f, a + (2 * k - 1) * h); 184 | end 185 | end 186 | 187 | for i = 1:n - 1 188 | % 1st column recursive trapezoid 189 | R(i + 1, 1) = R(i, 1) / 2; 190 | h = h / 2; 191 | 192 | % 4.1151 193 | % 0.0000 194 | 195 | 196 | end 197 | 198 | 199 | % 0.4365 200 | 201 | % r2 = 202 | 203 | function v = funItg3(x) 204 | v = sqrt(1 - x.^2) - x; 205 | end 206 | 207 | 208 | function v = polyvalue(a, x, t) 209 | % input: a= Newton's divided differences 210 | % x= the points for the data set to interpolate, 211 | % same as in divdiff. 212 | % t= the points where the polynomial should be evaluated 213 | % output: v= value of polynomial at the points in t 214 | ax = diag(a); 215 | t_size = size(t); 216 | [~, x_size] = size(x); 217 | v = zeros(t_size) + ax(1); 218 | cul = ones(t_size); 219 | for i = 2 : x_size 220 | cul = cul .* (t - x(i - 1)); 221 | v = v + ax(i) * cul; 222 | end 223 | end 224 | 225 | % ans = 226 | 227 | function v = funItg2(x) 228 | v = 3 .* x.^2; 229 | end 230 | 231 | 232 | for i=n-1:-1:2 233 | z(i) = (v(i)-h(i)*z(i+1))/u(i); 234 | end 235 | 236 | 237 | function x = GaussianX(n, d, a, b) 238 | % function x=GaussianX(n,d,a,b) 239 | % input: n: system size, must be odd 240 | % (d,a,b): vectors of length n 241 | % output: x=solution 242 | x = zeros(1, n); 243 | m = (n + 1) / 2; 244 | x(m) = b(m) / d(m); 245 | 246 | fr = feval(f, r); 247 | if abs(fr) < tol 248 | return; 249 | end 250 | 251 | while nit < nmax && norm(A * x - b) > tol 252 | y = zeros(n, 1); 253 | 254 | for k=1:n-1 255 | for i=k+1:n 256 | xmult = A(i,k)/A(k,k); 257 | A(i,k) = xmult; 258 | for j=k+1:n 259 | A(i,j) = A(i,j)-xmult*A(k,j); 260 | end 261 | b(i) = b(i)-xmult*b(k); 262 | end 263 | end 264 | disp(A); 265 | disp(b); 266 | x(n) = b(n)/A(n,n); 267 | for i=n-1:-1:1 268 | sum = b(i); 269 | for j=i+1:n 270 | sum = sum-A(i,j)*x(j); 271 | end 272 | x(i) = sum/A(i,i); 273 | end 274 | 275 | % result: 276 | % 277 | % >> myValue(1:10, -4:5) 278 | % 2629 279 | 280 | function r = bisection(f, a, b, tol, nmax) 281 | % function r=bisection(f,a,b,tol,nmax) 282 | % inputs: f: function handle or string 283 | % a,b: the interval where there is a root 284 | % tol: error tolerance 285 | % nmax: max number of iterations 286 | % output: r: a root 287 | fa = feval(f, a); 288 | if fa * feval(f, b) > 0 289 | error('f(a) * f(b) > 0'); 290 | end 291 | 292 | function x = mynewton(f, df, x0, tol, nmax) 293 | % input variables: 294 | % f,df are the function f and its derivative f', 295 | % x0 is the initial guess, 296 | % tol is the error tolerance, 297 | % and nmax is the maximum number of iterations. 298 | % The output variable: 299 | % x is the result of the Newton iterations. 300 | x = x0; 301 | fprintf('x = %g\n', x); 302 | if nmax <= 0 303 | return; 304 | end 305 | 306 | for i = 1:m - 1 307 | j = n - i + 1; 308 | sol = [d(i) a(j); a(i) d(j)] \ [b(i); b(j)]; 309 | x(i) = sol(1); 310 | x(j) = sol(2); 311 | end 312 | end 313 | 314 | 315 | function v = myValue(a, b) 316 | % input: a: vector 317 | % b: vector (same length as a) 318 | % output: v: the computed value 319 | res = 0; 320 | for i = 1:length(a) 321 | for j = 1:i 322 | res = res + b(i) * b(i) * a(j); 323 | end 324 | end 325 | v = res; 326 | end 327 | 328 | u(2) = 2*(h(1)+h(2)); 329 | v(2) = 6*(b(2)-b(1)); 330 | for i=3:n-1 % solve the tri-diag system 331 | u(i) = 2*(h(i)+h(i-1))-h(i-1)^2/u(i-1); 332 | v(i) = 6*(b(i)-b(i-1))-h(i-1)*v(i-1)/u(i-1); 333 | end 334 | 335 | fx1 = feval(f, x1); 336 | if abs(fx1) < tol 337 | return; 338 | end 339 | 340 | r = sum([a, b]) / 2; 341 | if nmax <= 0 342 | return; 343 | end 344 | 345 | fx0 = feval(f, x0); 346 | fr = (x1 - x0) / (fx1 - fx0); 347 | x = mysecant(f, x1, x - fr * fx1, tol, nmax - 1); 348 | end 349 | 350 | 351 | function [r1, r2] = smartquadroots(a, b, c) 352 | % input: a, b, c: coefficients for the polynomial ax^2+bx+c=0. 353 | % output: r1, r2: The two roots for the polynomial. 354 | rt = sqrt(b^2 - 4 * a * c); 355 | r1 =- (b + rt) / (2 * a); 356 | r2 = c / (a * r1); 357 | end 358 | 359 | % -1 360 | 361 | % -3.4365 362 | 363 | % 3.8348e+07 364 | 365 | % 7 366 | 367 | while nit < nmax && norm(A * x - b) > tol 368 | for i = 1:n 369 | aii = A(i, i); 370 | s1 = sum(A(i, 1:i - 1)' .* x(1:i - 1)); 371 | s2 = sum(A(i, i + 1:n)' .* x(i + 1:n)); 372 | sigma = s1 + s2; 373 | x(i) = (b(i) - sigma) / aii; 374 | end 375 | % fprintf("\\item $%.4f, %.4f, %.4f$\n", x(1), x(2), x(3)); 376 | disp(x); 377 | nit = nit + 1; 378 | end 379 | 380 | % >> [r1, r2] = quadroots(1, -14, 49) 381 | 382 | % 2 383 | 384 | % 1 385 | 386 | for i = 1:n 387 | aii = A(i, i); 388 | sigma = sum(A(i, 1:n)' .* x) - aii * x(i); 389 | y(i) = (b(i) - sigma) / aii; 390 | end 391 | 392 | % >> [r1, r2] = quadroots(1, -3, 2) 393 | 394 | function v = funItg(x) 395 | v=(x+1).^(-1); 396 | end 397 | 398 | 399 | % 1.0e+07 * 400 | 401 | function v = funItg4(x) 402 | if x == 0 403 | v = 1; 404 | else 405 | v = sin(x) ./ x; 406 | end 407 | end 408 | 409 | 410 | function v = trapezoid(s, a, b, n) 411 | % feval(s, a): call the function `f(a)` 412 | % [a, b]: the interval of integration 413 | % n: # of subintervals, so n+1 points 414 | h = (b - a) / n; 415 | x = a + h:h:b - h; 416 | v = ((feval(s, a) + feval(s, b)) / 2 + sum(feval(s, x))) * h; 417 | end 418 | 419 | 420 | % Forward elimination 421 | for j = 1:n - 1 422 | for i = j + 1:n 423 | p = A(i, j) / A(j, j); 424 | A(i, j:n) = A(i, j:n) - p * A(j, j:n); 425 | b(i) = b(i) - p * b(j); 426 | end 427 | end 428 | disp(full(A)); 429 | 430 | function [x, nit] = jacobi(A, b, x0, tol, nmax) 431 | % tol: error tolerance 432 | % nmax: max number of iterations 433 | % A, b: the matrix system 434 | % x0: initial guess 435 | % x: solution 436 | % nit: number of iterations used 437 | x = x0; 438 | n = length(x); 439 | nit = 0; 440 | 441 | function [x, nit] = sor(A, b, x0, w, d, tol, nmax) 442 | % SOR : solve linear system with SOR iteration 443 | % Usage: [x,nit]=sor(A,b,x0,omega,d,tol,nmax) 444 | % Inputs: 445 | % A : an n x n-matrix, 446 | % b : the rhs vector, with length n 447 | % x0 : the start vector for the iteration 448 | % tol: error tolerance 449 | % w: relaxation parameter, (1 < w < 2), 450 | % d : band width of A. 451 | % Outputs:: 452 | % x : the solution vector 453 | % nit: number of iterations 454 | x = x0; 455 | n = length(x); 456 | nit = 0; 457 | 458 | h = t(2:n)-t(1:n-1); 459 | b = (y(2:n)-y(1:n-1))./h; 460 | 461 | % r1 = 462 | 463 | % 7 464 | 465 | % >> [r1, r2] = quadroots(3, -123454321, 2) 466 | 467 | % x^2 + 2x + 1 ==> r1, r2 = -1 468 | % x^2 - 3x + 2 ==> r1 = 1, r2 = -2 469 | 470 | function [t, x] = rk4(f, t0, x0, tend, N) 471 | % f : Differential equation xp = f(t,x) 472 | % x0 : initial condition 473 | % t0,tend : initial and final time 474 | % N : number of time steps 475 | h = (tend - t0) / N; 476 | t = [t0:h:tend]; 477 | s = length(x0); % x0 can be a vector 478 | x = zeros(s, N + 1); 479 | x(:, 1) = x0; 480 | 481 | function z = cspline(t,y) 482 | % function z = cspline(t,y) 483 | % compute z-coefficients for natural cubic spline 484 | % where t is a vector with knots, and y is the interpolating values 485 | % z is the output vector 486 | 487 | for i = 1:n 488 | A(i, n - i + 1) = a(n - i + 1); 489 | A(i, i) = d(i); 490 | end 491 | 492 | % >> [r1, r2] = quadroots(1, 2, 1) 493 | 494 | while nit < nmax && norm(A * x - b) > tol 495 | for i = 1:n 496 | aii = A(i, i); 497 | s1 = sum(A(i, 1:i - 1)' .* x(1:i - 1)); 498 | s2 = sum(A(i, i + 1:n)' .* x(i + 1:n)); 499 | sigma = s1 + s2; 500 | new = (b(i) - sigma) / aii; 501 | x(i) = x(i) * (1 - w) + w * new; 502 | end 503 | disp(x); 504 | nit = nit + 1; 505 | end 506 | end 507 | 508 | 509 | function x = naiv_gauss(A,b) 510 | n = length(b); 511 | x = zeros(n,1); 512 | 513 | function [r1, r2] = quadroots(a, b, c) 514 | % input: a, b, c: coefficients for the polynomial ax^2+bx+c=0. 515 | % output: r1, r2: The two roots for the polynomial. 516 | rt = sqrt(b^2 - 4 * a * c); 517 | r1 =- (b + rt) / (2 * a); 518 | r2 =- (b - rt) / (2 * a); 519 | end -------------------------------------------------------------------------------- /files/assembly.v: -------------------------------------------------------------------------------- 1 | module DataPath( 2 | input clk, 3 | output [31:0] pc_r, 4 | output ewreg, 5 | output em2reg, 6 | output ewmem, 7 | output ealuimm, 8 | output [3:0] ealuc, 9 | output [4:0] edest_reg, 10 | output [31:0] eqa, 11 | output [31:0] eqb, 12 | output [31:0] eimm32, 13 | output mwreg, 14 | output mm2reg, 15 | output mwmem, 16 | output [31:0] mr, 17 | output [31:0] mqb, 18 | output [4:0] mdestreg, 19 | output wwreg, 20 | output wm2reg, 21 | output [4:0] wdestreg, 22 | output [31:0] wr, 23 | output [31:0] wdo 24 | ); 25 | wire [31:0] add_rs, inst, dinst; 26 | wire wreg, m2reg, wmem, aluimm, regrt; 27 | wire [3:0] aluc_dp; 28 | wire [4:0] dest_reg; 29 | wire [31:0] qa_dp, qb_dp, imm32; 30 | wire [31:0] mdo; 31 | 32 | module Immediate_Extender( 33 | input [31:0] dinst_out, 34 | output reg [31:0] imm32 35 | ); 36 | wire [15:0] imm = dinst_out[15:0]; 37 | always@(imm) begin 38 | imm32 <= {{16{imm[15]}}, imm[15:0]}; 39 | end 40 | endmodule 41 | 42 | `timescale 1ns / 1ps 43 | ////////////////////////////////////////////////////////////////////////////////// 44 | // Company: 45 | // Engineer: 46 | // 47 | // Create Date: 05/18/2020 12:27:00 PM 48 | // Design Name: 49 | // Module Name: testbench 50 | // Project Name: 7 segment display 51 | // Target Devices: 52 | // Tool Versions: 53 | // Description: 54 | // 55 | // Dependencies: 56 | // 57 | // Revision: 58 | // Revision 0.01 - File Created 59 | // Additional Comments: 60 | // 61 | ////////////////////////////////////////////////////////////////////////////////// 62 | 63 | `timescale 1ns / 1ps 64 | ////////////////////////////////////////////////////////////////////////////////// 65 | // Create Date: 2022/02/06 21:23:55 66 | // Module Name: test_bench 67 | // 68 | ////////////////////////////////////////////////////////////////////////////////// 69 | 70 | // "Instruction memory" 71 | module InstMem(input [31:0] pc, output reg [31:0] inst_out); 72 | reg [31:0] memory [0:63]; 73 | initial begin 74 | memory[25] <= 32'b10001100001000100000000000000000; 75 | memory[26] <= 32'b10001100001000110000000000000100; 76 | end 77 | always @ (pc) 78 | begin 79 | inst_out <= memory[pc[31:2]]; 80 | end 81 | endmodule 82 | 83 | module Register_File( 84 | input clk, 85 | input [4:0] wdestreg, 86 | input [31:0] wbdata, 87 | input wwreg, 88 | input [31:0] dinst_out, 89 | output reg [31:0] qa, 90 | output reg [31:0] qb 91 | ); 92 | reg [31:0] registers; 93 | integer i; 94 | 95 | module DataPath( 96 | input clk, 97 | output [31:0] pc_r, 98 | output ewreg, 99 | output em2reg, 100 | output ewmem, 101 | output ealuimm, 102 | output [3:0] ealuc, 103 | output [4:0] edest_reg, 104 | output [31:0] eqa, 105 | output [31:0] eqb, 106 | output [31:0] eimm32, 107 | output mwreg, 108 | output mm2reg, 109 | output mwmem, 110 | output [31:0] mr, 111 | output [31:0] mqb, 112 | output [4:0] mdestreg, 113 | output wwreg, 114 | output wm2reg, 115 | output [4:0] wdestreg, 116 | output [31:0] wr, 117 | output [31:0] wdo 118 | ); 119 | wire [31:0] add_rs, inst, dinst; 120 | wire wreg, m2reg, wmem, aluimm, regrt; 121 | wire [3:0] aluc_dp; 122 | wire [4:0] dest_reg; 123 | wire [31:0] qa_dp, qb_dp, imm32; 124 | wire [31:0] mdo; 125 | wire [31:0] wb_out; 126 | 127 | // Module : Up/Down Counter 128 | // Description : Combinational circuit that generates the next state and LED control signals based on input u 129 | // Input(s) : 3-bit Current State, 1-bit u 130 | // Output(s) : 3-bit Next State, 7 1-bit segments of the LED 131 | module counter(input [2:0] q, input u, output reg [2:0] ns, 132 | output reg a, output reg b, output reg c, output reg d, output reg e, output reg f, output reg g ); 133 | always @(*) 134 | begin 135 | if (u == 1) begin 136 | if (q == 3'b101) begin 137 | ns <= 3'b000; 138 | end 139 | else begin 140 | ns <= q + 1; 141 | end 142 | end 143 | else begin 144 | if (q == 3'b000) begin 145 | ns <= 3'b101; 146 | end 147 | else begin 148 | ns <= q - 1; 149 | end 150 | end 151 | case(q) 152 | 3'b000: begin 153 | g=1'b1; f=1'b0; e=1'b0; d=1'b0; c=1'b0; b=1'b0; a=1'b0; 154 | end 155 | 3'b001: begin 156 | g=1'b1; f=1'b1; e=1'b1; d=1'b1; c=1'b0; b=1'b0; a=1'b1; 157 | end 158 | 3'b010: begin 159 | g=1'b0; f=1'b1; e=1'b0; d=1'b0; c=1'b1 ;b=1'b0; a=1'b0; 160 | end 161 | 3'b011: begin 162 | g=1'b0; f=1'b1; e=1'b1; d=1'b0; c=1'b0; b=1'b0; a=1'b0; 163 | end 164 | 3'b100: begin 165 | g=1'b0; f=1'b0; e=1'b1; d=1'b1; c=1'b0; b=1'b0; a=1'b1; 166 | end 167 | 3'b101: begin 168 | g=1'b0; f=1'b0; e=1'b1; d=1'b0; c=1'b0; b=1'b1; a=1'b0; 169 | end 170 | endcase 171 | end 172 | endmodule 173 | 174 | // Module : Testbench 175 | // Description : Using the test sequence given generate the output of the 7 segment display by calling dff3 and counter modules 176 | module testbench(); 177 | reg clrn_tb; 178 | reg clk_tb; 179 | reg u_tb; 180 | wire [2:0] q_tb; 181 | wire [2:0] ns_tb; 182 | wire a,b,c,d,e,f,g; 183 | dff3 dff3_tb(ns_tb, clrn_tb, clk_tb, q_tb); 184 | counter counter_tb(q_tb, u_tb, ns_tb, a, b, c, d, e, f, g); 185 | initial begin 186 | clrn_tb = 0; 187 | clk_tb = 1; 188 | u_tb = 1; 189 | #1 clrn_tb = 1; 190 | #16 u_tb = 0; 191 | end 192 | always begin 193 | #1; 194 | clk_tb = ~clk_tb; 195 | end 196 | endmodule 197 | 198 | module PC_Adder( 199 | input [31:0] pc, 200 | output reg [31:0] new 201 | ); 202 | initial begin 203 | new <= 32'd100; 204 | end 205 | always @(pc) begin 206 | new <= pc + 32'd4; 207 | end 208 | endmodule 209 | 210 | // ===== Lab 4 ===== 211 | wire mwreg, mm2reg, mwmem; 212 | wire [31:0] mr, mqb; 213 | wire [4:0] mdestreg; 214 | wire wwreg, wm2reg; 215 | wire [31:0] wr, wdo; 216 | wire [4:0] wdestreg; 217 | // ===== Lab 4 ===== 218 | 219 | module Register_File( 220 | input [31:0] dinst_out, 221 | output reg [31:0] qa, 222 | output reg [31:0] qb 223 | ); 224 | reg [31:0] registers; 225 | integer i; 226 | 227 | PC pc_dp(clk, add_rs, pc_r); 228 | PC_Adder adder_dp(pc_r, add_rs); 229 | InstMem im_dp(pc_r, inst); 230 | IF_ID ifid_dp(clk, inst, dinst); 231 | Control_Unit cu_dp(dinst, wreg, m2reg, wmem, aluc_dp, aluimm, regrt); 232 | Regrt_Multiplexer mult_dp(dinst, regrt, dest_reg); 233 | Register_File rf_dp(dinst, qa_dp, qb_dp); 234 | Immediate_Extender ie_dp(dinst, imm32); 235 | ID_EXE idexe_dp(clk, wreg, m2reg, wmem, aluc_dp, aluimm, dest_reg, qa_dp, qb_dp, imm32, ewreg, em2reg, ewmem, ealuc, ealuimm, edest_reg, eqa, eqb, eimm32); 236 | endmodule 237 | 238 | 239 | // Program counter 240 | module PC( 241 | input clk, 242 | input [31:0] new_addr, 243 | output reg [31:0] pc 244 | ); 245 | always @(posedge clk) begin 246 | pc <= new_addr; 247 | end 248 | endmodule 249 | 250 | module Control_Unit( 251 | // Decomposed into op and func 252 | input [31:0] dinst_out, 253 | output reg wreg, 254 | output reg m2reg, 255 | output reg wmem, 256 | output reg [3:0] aluc, 257 | output reg aluimm, 258 | output reg regrt 259 | ); 260 | reg [5:0] op; 261 | reg [5:0] func; 262 | always @ (dinst_out) begin 263 | op <= dinst_out[31:26]; 264 | func <= dinst_out[5:0]; 265 | case(op) 266 | // r-type 267 | 6'b000000: begin 268 | case(func) 269 | // TODO 270 | endcase 271 | end 272 | // lw 273 | 6'b100011: begin 274 | wreg = 1'b1; 275 | m2reg = 1'b1; 276 | wmem = 1'b0; 277 | aluc = 4'b0010; 278 | aluimm = 1'b1; 279 | regrt = 1'b1; 280 | end 281 | endcase 282 | end 283 | endmodule 284 | 285 | module ID_EXE( 286 | input clk, 287 | input wreg, 288 | input m2reg, 289 | input wmem, 290 | input [3:0] aluc, 291 | input aluimm, 292 | input [4:0] dest_reg, 293 | input [4:0] qa, 294 | input [4:0] qb, 295 | input [31:0] imm32, 296 | output reg ewreg, 297 | output reg em2reg, 298 | output reg ewmem, 299 | output reg [3:0] ealuc, 300 | output reg ealuimm, 301 | output reg [4:0] edest_reg, 302 | output reg [31:0] eqa, 303 | output reg [31:0] eqb, 304 | output reg [31:0] eimm32 305 | ); 306 | always@(posedge clk) begin 307 | ewreg <= wreg; 308 | em2reg <= m2reg; 309 | ewmem <= wmem; 310 | ealuc <= aluc; 311 | ealuimm <= aluimm; 312 | edest_reg <= dest_reg; 313 | eqa <= qa; 314 | eqb <= qb; 315 | eimm32 <= imm32; 316 | end 317 | endmodule 318 | 319 | module ExememPipe( 320 | input clk, 321 | input ewreg, 322 | input em2reg, 323 | input ewmem, 324 | input [4:0] edestreg, 325 | input [31:0] alul_out, 326 | input [31:0] eqb, 327 | output reg mwreg, 328 | output reg mm2reg, 329 | output reg mwmem, 330 | output reg [4:0] mdestreg, 331 | output reg [31:0] mr, 332 | output reg [31:0] mqb 333 | ); 334 | always @(posedge clk) begin 335 | mwreg = ewreg; 336 | mm2reg = em2reg; 337 | mwmem = ewmem; 338 | mdestreg = edestreg; 339 | mr = alul_out; 340 | mqb = eqb; 341 | end 342 | endmodule 343 | 344 | module ALU_Logic( 345 | input [31:0] eqa, 346 | input [31:0] alu_out, 347 | input [3:0] ealuc, 348 | output reg [31:0] alul_out 349 | ); 350 | always @(*) begin 351 | if (ealuc == 4'b0000) begin 352 | alul_out <= eqa & alu_out; 353 | end else if (ealuc == 4'b0001) begin 354 | alul_out <= eqa | alu_out; 355 | end else if (ealuc == 4'b0010) begin 356 | alul_out <= eqa + alu_out; 357 | end else if (ealuc == 4'b0110) begin 358 | alul_out <= eqa - alu_out; 359 | end else if (ealuc == 4'b0111) begin 360 | alul_out <= eqa < alu_out ? 1:0; 361 | end else if (ealuc == 4'b1100) begin 362 | alul_out <= ~(eqa | alu_out); 363 | end 364 | end 365 | endmodule 366 | 367 | PC pc_dp(clk, add_rs, pc_r); 368 | PC_Adder adder_dp(pc_r, add_rs); 369 | InstMem im_dp(pc_r, inst); 370 | IF_ID ifid_dp(clk, inst, dinst); 371 | Control_Unit cu_dp(dinst, wreg, m2reg, wmem, aluc_dp, aluimm, regrt); 372 | Regrt_Multiplexer mult_dp(dinst, regrt, dest_reg); 373 | Register_File rf_dp(clk, wdestreg, wb_out, wwreg, dinst, qa_dp, qb_dp); 374 | WriteBack_Mux wb(wm2reg, wr, wdo, wb_out); 375 | Immediate_Extender ie_dp(dinst, imm32); 376 | ID_EXE idexe_dp(clk, wreg, m2reg, wmem, aluc_dp, aluimm, dest_reg, qa_dp, qb_dp, imm32, ewreg, em2reg, ewmem, ealuc, ealuimm, edest_reg, eqa, eqb, eimm32); 377 | 378 | module DataPath( 379 | input clk, 380 | output [31:0] pc_r, 381 | output ewreg, 382 | output em2reg, 383 | output ewmem, 384 | output ealuimm, 385 | output [3:0] ealuc, 386 | output [4:0] edest_reg, 387 | output [31:0] eqa, 388 | output [31:0] eqb, 389 | output [31:0] eimm32 390 | ); 391 | wire [31:0] add_rs, inst, dinst; 392 | wire wreg, m2reg, wmem, aluimm, regrt; 393 | wire [3:0] aluc_dp; 394 | wire [4:0] dest_reg; 395 | wire [31:0] qa_dp, qb_dp, imm32; 396 | 397 | module MEMWB( 398 | input clk, 399 | input mwreg, 400 | input mm2reg, 401 | input [4:0] mdestreg, 402 | input [31:0] mr, 403 | input [31:0] mdo, 404 | output reg wwreg, 405 | output reg wm2reg, 406 | output reg [4:0] wdestreg, 407 | output reg [31:0] wr, 408 | output reg [31:0] wdo 409 | ); 410 | always @(posedge clk) begin 411 | wwreg = mwreg; 412 | wm2reg = mm2reg; 413 | wdestreg = mdestreg; 414 | wr = mr; 415 | wdo = mdo; 416 | end 417 | endmodule 418 | 419 | // Local states 420 | reg [31:0] reg_q; 421 | reg [15:0] reg_r; 422 | reg [15:0] reg_b; 423 | reg [4:0] count; 424 | 425 | `timescale 1ns / 1ps 426 | // Module : D flip-flop 427 | // Description : At the positive edge of the clock, set the current state based on the clear 428 | // Input(s) : 3-bit Next State, Clear and Clock 429 | // Output(s) : 3-bit Current State 430 | module dff3(input [2:0] ns, input clrn, input clk, output reg [2:0] q); 431 | always @ (posedge clk) 432 | begin 433 | if (clrn == 1) begin 434 | q <= ns; 435 | end 436 | else begin 437 | q <= 3'b000; 438 | end 439 | end 440 | endmodule 441 | 442 | module test_bench(); 443 | reg clr, start, clk; 444 | reg [31:0] a; 445 | reg [15:0] b; 446 | wire [31:0] q; 447 | wire [15:0] r; 448 | wire busy, ready; 449 | wire [4:0] count; 450 | main divider(a, b, q, r, start, clk, clr, busy, ready, count); 451 | initial begin 452 | clr <= 0; 453 | start <= 0; 454 | // As described in the lab instructions 455 | a <= 32'h4c7f228a; 456 | b <= 16'h6a0e; 457 | clk <= 1; 458 | // Run simulation 459 | #5 clr <= 1; 460 | #0 start <= 1; 461 | #10 start <= 0; 462 | end 463 | always begin 464 | // Negate the clock 465 | #5 clk = ~clk; 466 | end 467 | endmodule 468 | 469 | 470 | module WriteBack_Mux( 471 | input wm2reg, 472 | input [31:0] wr, 473 | input [31:0] wdo, 474 | output reg [31:0] wb_out 475 | ); 476 | always@(*) begin 477 | if (wm2reg == 0) begin 478 | wb_out <= wr; 479 | end else begin 480 | wb_out <= wdo; 481 | end 482 | end 483 | endmodule 484 | 485 | PC pc_dp(clk, add_rs, pc_r); 486 | PC_Adder adder_dp(pc_r, add_rs); 487 | InstMem im_dp(pc_r, inst); 488 | IF_ID ifid_dp(clk, inst, dinst); 489 | Control_Unit cu_dp(dinst, wreg, m2reg, wmem, aluc_dp, aluimm, regrt); 490 | Regrt_Multiplexer mult_dp(dinst, regrt, dest_reg); 491 | Register_File rf_dp(dinst, qa_dp, qb_dp); 492 | Immediate_Extender ie_dp(dinst, imm32); 493 | ID_EXE idexe_dp(clk, wreg, m2reg, wmem, aluc_dp, aluimm, dest_reg, qa_dp, qb_dp, imm32, ewreg, em2reg, ewmem, ealuc, ealuimm, edest_reg, eqa, eqb, eimm32); 494 | 495 | always @(posedge clk or negedge clr) begin 496 | if (!clr) begin 497 | busy <= 0; 498 | ready <= 0; 499 | end else begin 500 | if (start) begin 501 | // Initialize in parallel 502 | reg_q <= a; 503 | reg_b <= b; 504 | reg_r <= 0; 505 | busy <= 1; 506 | ready <= 0; 507 | count <= 0; 508 | end else if (busy) begin 509 | reg_q <= {reg_q[30:0], ~sub_out[16]}; 510 | reg_r <= mux_out; 511 | count <= count + 5'b1; 512 | // Computation completed. 513 | if (count + 1 == 5'b0) begin 514 | busy <= 0; 515 | ready <= 1; 516 | end 517 | end 518 | end 519 | end 520 | endmodule 521 | 522 | 523 | module ALU(input [31:0] eqb, input [31:0] eimm32, input ealuimm, output reg [31:0] alu_out); 524 | always @(*) begin 525 | if (ealuimm) begin 526 | alu_out = eimm32; 527 | end else begin 528 | alu_out = eqb; 529 | end 530 | end 531 | endmodule 532 | 533 | `timescale 1ns / 1ps 534 | // Create Date: 2022/03/20 21:22:36 535 | module tb(); 536 | reg clk; 537 | wire [31:0] pc_r; 538 | wire ewreg; 539 | wire em2reg; 540 | wire ewmem; 541 | wire ealuimm; 542 | wire [3:0] ealuc; 543 | wire [4:0] edest_reg; 544 | wire [31:0] eimm32, eqa, eqb; 545 | initial begin 546 | clk = 1; 547 | end 548 | DataPath dp(clk, pc_r, ewreg, em2reg, ewmem, ealuimm, ealuc, edest_reg, eqa, eqb, eimm32); 549 | always begin 550 | #5 clk = ~clk; 551 | end 552 | endmodule 553 | 554 | 555 | initial begin 556 | for (i = 0; i < 32; i = i + 1) begin 557 | registers[i] <= 32'b0; 558 | end 559 | end 560 | 561 | module Regrt_Multiplexer( 562 | input [31:0] dinst_out, 563 | input regrt, 564 | output reg [4:0] dest_reg 565 | ); 566 | always @ (*) begin 567 | if (regrt == 0) begin 568 | // rd 569 | dest_reg <= dinst_out[15:11]; 570 | end else begin 571 | // rt 572 | dest_reg <= dinst_out[20:16]; 573 | end 574 | end 575 | endmodule 576 | 577 | `timescale 1ns / 1ps 578 | // Create Date: 2022/03/20 21:22:36 579 | module tb(); 580 | reg clk; 581 | wire [31:0] pc_r; 582 | wire ewreg; 583 | wire em2reg; 584 | wire ewmem; 585 | wire ealuimm; 586 | wire [3:0] ealuc; 587 | wire [4:0] edest_reg; 588 | wire [31:0] eimm32, eqa, eqb; 589 | 590 | always @ (dinst_out) begin 591 | qa <= registers[dinst_out[25:21]]; 592 | qb <= registers[dinst_out[20:16]]; 593 | end 594 | endmodule 595 | 596 | module IF_ID(input clk, input [31:0] inst_out, output reg [31:0] dinst_out); 597 | always@(posedge clk) 598 | begin 599 | dinst_out <= inst_out; 600 | end 601 | endmodule 602 | 603 | wire [31:0] alu_out; 604 | wire [31:0] alul_out; 605 | ALU alu_mux(eqb, eimm32, ealuimm, alu_out); 606 | ALU_Logic alu(eqa, alu_out, ealuc, alul_out); 607 | ExememPipe pipe(clk, ewreg, em2reg, ewmem, edestreg, alul_out, eqb, mwreg, mm2reg, mwmem, mdestreg, mr, mqb); 608 | MEMWB mb(clk, mwreg, mm2reg, mdestreg, mr, mdo, wwreg, wm2reg, wdestreg, wr, wdo); 609 | endmodule 610 | 611 | 612 | initial begin 613 | clk = 1; 614 | end 615 | DataPath dp(clk, pc_r, 616 | ewreg, em2reg, ewmem, ealuimm, ealuc, edest_reg, eqa, eqb, eimm32, 617 | mwreg, mm2reg, mwmem, mr, mqb, mdestreg, wwreg, wm2reg, wdestreg, wr, wdo 618 | ); 619 | always begin 620 | #5 clk = ~clk; 621 | end 622 | endmodule 623 | 624 | 625 | // Subtract r and q with 0 and b 626 | wire [16:0] sub_out = {reg_r, reg_q[31]} - {1'b0, reg_b}; 627 | // Controlled 628 | wire [15:0] mux_out = sub_out[16] ? {reg_r[14:0], reg_q[31]} : sub_out[15:0]; 629 | assign q = reg_q; 630 | assign r = reg_r; 631 | 632 | `timescale 1ns / 1ps 633 | ////////////////////////////////////////////////////////////////////////////////// 634 | // Company: 635 | // Engineer: 636 | // 637 | // Create Date: 2022/02/06 20:16:41 638 | // Design Name: 639 | // Module Name: main 640 | // Project Name: Cmpen 331 Lab 1 641 | // Target Devices: As described on PDF 642 | // Description: division 643 | // 644 | ////////////////////////////////////////////////////////////////////////////////// 645 | 646 | module DataMem(input [31:0] mr, input [31:0] mqb, input mwmem, input clk, output reg [31:0] mdo); 647 | reg [31:0] data [0:63]; 648 | initial begin 649 | data[0] = 32'hA00000AA; 650 | data[4] = 32'h10000011; 651 | data[8] = 32'h20000022; 652 | data[12] = 32'h30000033; 653 | data[16] = 32'h40000044; 654 | data[20] = 32'h50000055; 655 | data[24] = 32'h60000066; 656 | data[28] = 32'h70000077; 657 | data[32] = 32'h80000088; 658 | data[36] = 32'h90000099; 659 | end 660 | always @(*) begin 661 | mdo = data[mr]; 662 | end 663 | always @(negedge clk)begin 664 | if (mwmem == 1) begin 665 | data[mr] = mqb; 666 | end 667 | end 668 | endmodule 669 | 670 | initial begin 671 | clk = 1; 672 | end 673 | DataPath dp(clk, 674 | // pc_r, 675 | // ewreg, em2reg, ewmem, ealuimm, ealuc, edest_reg, eqa, eqb, eimm32, 676 | // mwreg, mm2reg, mwmem, mr, mqb, mdestreg, wwreg, wm2reg, wdestreg, 677 | wwreg, wm2reg, 678 | wdestreg, 679 | wr, wdo 680 | wbdataout, r_s, r_t, qa, qb,r 681 | ); 682 | always begin 683 | #5 clk = ~clk; 684 | end 685 | endmodule 686 | 687 | 688 | // "Instruction memory" 689 | module InstMem(input [31:0] pc, output reg [31:0] inst_out); 690 | reg [31:0] memory [0:63]; 691 | initial begin 692 | memory[25] <= 32'b10001100001000100000000000000000; 693 | memory[26] <= 32'b10001100001000110000000000000100; 694 | memory[27] <= 32'b10001100001001000000000000001000; 695 | memory[28] <= 32'b10001100001001010000000000001100; 696 | end 697 | always @ (pc) 698 | begin 699 | inst_out <= memory[pc[31:2]]; 700 | end 701 | endmodule 702 | 703 | // Implementation details 704 | input start, clk, clr; 705 | output reg busy, ready; 706 | output [4:0] count; 707 | 708 | `timescale 1ns / 1ps 709 | // Create Date: 2022/03/20 14:43:52 710 | // Design Name: 711 | 712 | module main(a, b, q, r, start, clk, clr, busy, ready, count); 713 | // "Intended to be seen by other modules" I/O 714 | input [31:0] a; 715 | input [15:0] b; 716 | output [31:0] q; 717 | output [15:0] r; 718 | 719 | module Control_Unit( 720 | // Decomposed into op and func 721 | input [31:0] dinst_out, 722 | output reg wreg, 723 | output reg m2reg, 724 | output reg wmem, 725 | output reg [3:0] aluc, 726 | output reg aluimm, 727 | output reg regrt 728 | ); 729 | reg [5:0] op; 730 | reg [5:0] func; 731 | always @ (dinst_out) begin 732 | op <= dinst_out[31:26]; 733 | func <= dinst_out[5:0]; 734 | case(op) 735 | // r-type 736 | 6'b000000: begin 737 | // TODO 738 | end 739 | // lw 740 | 6'b100011: begin 741 | wreg = 1'b1; 742 | m2reg = 1'b1; 743 | wmem = 1'b0; 744 | aluc = 4'b0010; 745 | aluimm = 1'b1; 746 | regrt = 1'b1; 747 | end 748 | endcase 749 | end 750 | endmodule -------------------------------------------------------------------------------- /files/assembly.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Initialize: returns false on error, true on success. 3 | */ 4 | bool mm_init(void) { 5 | heap_data = mem_sbrk((intptr_t) align(sizeof(*heap_data)) + 8); 6 | if (is_sbrk_invalid(heap_data)) return false; 7 | if (DEBUG) printf("Init 88: the heap is being created, heap_data = %p\n", heap_data); 8 | heap_data->free_block_count = 0; 9 | heap_data->head = NULL; 10 | heap_data->tail = NULL; 11 | heap_data->last_block = NULL; 12 | heap_data->first_block = ((word_t *) heap_data) + 0xFFFF; 13 | heap_data->alloc_unit = 1 << 14; 14 | word_t *root = grow_heap(0); 15 | if (!root) return false; 16 | heap_data->first_block = root; 17 | heap_data->head = root; 18 | return true; 19 | } 20 | 21 | /** 22 | * realloc 23 | */ 24 | void *realloc(void *oldptr, size_t size) { 25 | if (!size) { 26 | free(oldptr); 27 | return NULL; 28 | } 29 | word_t *base_addr = ((word_t *) oldptr) - 1; 30 | word_t old_size = information(base_addr).size; 31 | if (DEBUG) printf("Realloc: base_addr = %p, size = %zu -> %zu\n", base_addr, old_size, size); 32 | if (old_size >= size) { 33 | // TODO: for enhancement, we can shrink the block. 34 | return oldptr; 35 | } 36 | // New pointer 37 | word_t *atarashi = malloc(size); 38 | // Copy old data to new pointer 39 | mem_memcpy(atarashi, oldptr, size); 40 | free(oldptr); 41 | return atarashi; 42 | } 43 | 44 | if (already_closed(buffer)) return CLOSED_ERROR; 45 | size_t msg_size = my_get_msg_size(data); 46 | 47 | /// Remove base_addr from the free list. 48 | static void remove_block(const word_t *base_addr) { 49 | word_t *ptr_prev = prev_block(base_addr); 50 | word_t *ptr_next = next_block(base_addr); 51 | // Reconnect 52 | insert_before(ptr_prev, ptr_next); 53 | // Check head 54 | if (heap_data->head == base_addr) { 55 | heap_data->head = ptr_next; 56 | } 57 | // Check tail 58 | if (heap_data->tail == base_addr) { 59 | heap_data->tail = ptr_prev; 60 | } 61 | heap_data->free_block_count--; 62 | } 63 | 64 | JBOD from_command(jbod_cmd_t cmd) { 65 | JBOD jbod; 66 | jbod.command = cmd; 67 | return jbod; 68 | } 69 | 70 | /** 71 | * Returns whether the pointer is aligned. 72 | * May be useful for debugging. 73 | */ 74 | static bool aligned(const void *p) { 75 | size_t ip = (size_t) p; 76 | return align(ip) == ip; 77 | } 78 | 79 | enum buffer_status buffer_receive(state_t *buffer, void **data) { 80 | enum buffer_status status; 81 | 82 | if (!buffer->isopen) { 83 | // already closed, unlock in reverse order 84 | run_both(pthread_mutex_unlock, &buffer->chmutex, &buffer->chclose); 85 | return CLOSED_ERROR; 86 | } 87 | buffer->isopen = false; 88 | 89 | // Takes an array of integers and the length of the array as input, and returns the smallest integer in the array 90 | int smallest(int array[], int length) { 91 | // Simple traversal with empty array special case 92 | if (length <= 0) return 0; 93 | int smallest = array[0], i; 94 | for (i = 1; i < length; ++i) smallest = smallest < array[i] ? smallest : array[i]; 95 | return smallest; 96 | } 97 | 98 | // Any formatter will break this gorgeous, beautiful typsetting 99 | // Please be merciful formatting this document 100 | bool invalid_state(int disk_num, int block_num, const uint8_t *buf) { 101 | return !cache || !buf 102 | || disk_num < 0 || block_num < 0 103 | || disk_num >= JBOD_NUM_DISKS || block_num >= JBOD_BLOCK_SIZE; 104 | } 105 | 106 | void cache_print_hit_rate(void) { 107 | fprintf(stderr, "Hit rate: %5.1f%%\n", 100 * (float) num_hits / num_queries); 108 | } 109 | 110 | 111 | /// Just a synonym 112 | int apply_cmd(JBOD cmd, uint8_t *buf) { 113 | return jbod_client_operation(*((uint32_t*) &cmd), buf); 114 | } 115 | 116 | while (msg_size >= fifo_avail_size(buffer->fifoQ)) { 117 | pthread_cond_wait(&buffer->chconsend, &buffer->chmutex); 118 | 119 | #include "cache.h" 120 | 121 | // Two typos in the above comment 122 | 123 | /// Because the teaching team is not capable of using Clang-Tidy 124 | /// or realize that this is a narrowing conversion, we have our own version 125 | /// of get_msg_size 126 | size_t my_get_msg_size(char *data) { 127 | return sizeof(int) + strlen(data) + 1; 128 | } 129 | 130 | if (BUFFER_SUCCESS == (status = buffer_add_Q(buffer, data))) { 131 | pthread_cond_signal(&buffer->chconrec); 132 | } 133 | 134 | uint8_t cache[JBOD_BLOCK_SIZE]; 135 | uint32_t read_len = len; 136 | while (read_len > 0) { 137 | if (cached_read(cache, cmd, true)) return -1; 138 | uint32_t current_read_len = read_len > JBOD_BLOCK_SIZE ? JBOD_BLOCK_SIZE : read_len; 139 | if (block_offset > 0) { 140 | uint32_t max_can_read = JBOD_BLOCK_SIZE - block_offset; 141 | if (max_can_read < current_read_len) current_read_len = max_can_read; 142 | memcpy(buf, cache + block_offset, current_read_len); 143 | block_offset = 0; 144 | } else memcpy(buf, cache, current_read_len); 145 | buf += current_read_len; 146 | read_len -= current_read_len; 147 | if (inc_block(&cmd)) return -1; 148 | } 149 | return len; 150 | } 151 | 152 | /// Just a wrapper of unpack 153 | static block_info information(const word_t *base_addr) { 154 | return unpack(*base_addr); 155 | } 156 | 157 | /// Modify the pointer to the previous block. 158 | inline static void modify_prev(word_t *base_addr, const word_t *pointed_addr) { 159 | *(base_addr + 2) = (word_t) pointed_addr; 160 | } 161 | 162 | // Frees all the memory allocated to the buffer , using own version of sem flags 163 | // The caller is responsible for calling buffer_close and waiting for all threads to finish their tasks before calling buffer_destroy 164 | // Returns BUFFER_SUCCESS if destroy is successful, 165 | // DESTROY_ERROR if buffer_destroy is called on an open buffer, and 166 | // BUFFER_ERROR in any other error case 167 | 168 | // lock mutex for close and buffer 169 | run_both(pthread_mutex_lock, &buffer->chclose, &buffer->chmutex); 170 | 171 | /// Insert ptr_middle to the place before ptr_next (usually heap_data->head). 172 | static void insert_before(word_t *ptr_middle, word_t *ptr_next) { 173 | if (ptr_middle) modify_next(ptr_middle, ptr_next); 174 | if (ptr_next) { 175 | modify_prev(ptr_next, ptr_middle); 176 | // (*heap_data).head 177 | if (heap_data->head == ptr_next && ptr_middle) { 178 | heap_data->head = ptr_middle; 179 | } 180 | } else if (ptr_middle) { 181 | heap_data->tail = ptr_middle; 182 | } 183 | } 184 | 185 | // A naive algorithm for testing prime numbers 186 | int is_prime(int n) { 187 | int i; 188 | if (n < 0) return 0; 189 | for (i = 2; i * i <= n; ++i) 190 | // Not a prime 191 | if (n % i == 0) return 0; 192 | // Is a prime 193 | return 1; 194 | } 195 | 196 | // wait for messages 197 | while (buffer->fifoQ->avilSize >= buffer->fifoQ->size) { 198 | pthread_cond_wait(&buffer->chconrec, &buffer->chmutex); 199 | 200 | /// Inserts a block into the free list, between ptr_prev and ptr_next. 201 | static void insert(word_t *ptr_middle, word_t *ptr_prev, word_t *ptr_next) { 202 | if (ptr_middle) { 203 | modify_prev(ptr_middle, ptr_prev); 204 | if (ptr_prev) { 205 | modify_next(ptr_prev, ptr_middle); 206 | } else { 207 | heap_data->head = ptr_middle; 208 | } 209 | } 210 | insert_before(ptr_middle, ptr_next); 211 | } 212 | 213 | /** 214 | * malloc 215 | */ 216 | void *malloc(size_t size) { 217 | if (size == 0) return NULL; 218 | // Translate from bytes to words 219 | size = align(size) / 8 + INFO_SIZE; 220 | if (DEBUG) printf("Malloc: size in words: %zu\n", size); 221 | // From now on, size is the size of the requested block. 222 | word_t *ptr = heap_data->head; 223 | block_info info; 224 | // Trick: the first free block available 225 | word_t *ptr_first = NULL; 226 | block_info info_first; 227 | // This initialization is useless, we write it to make gcc happy 228 | info_first.size = 0; 229 | info_first.occupied = 0; 230 | while (true) { 231 | // Just in case the head is also null, we check it first 232 | if (!ptr) { 233 | // Only one block is available 234 | if (ptr_first) { 235 | ptr = ptr_first; 236 | info = info_first; 237 | break; 238 | } 239 | ptr = grow_heap(size); 240 | } 241 | if (!ptr) return NULL; 242 | info = information(ptr); 243 | // Lucky 244 | if (info.size >= size) { 245 | if (!ptr_first) { 246 | // This is the first block we've found 247 | ptr_first = ptr; 248 | info_first = info; 249 | } else { 250 | // Found 2 blocks, choose the smaller one 251 | if (info_first.size < info.size) { 252 | ptr = ptr_first; 253 | info = info_first; 254 | } 255 | break; 256 | } 257 | } 258 | ptr = next_block(ptr); 259 | } 260 | if (!heap_data->head) heap_data->head = ptr; 261 | if (DEBUG) printf("Malloc: chosen ptr = %p, size = %lu, occ = %i\n", ptr, info.size, info.occupied); 262 | // info.size - size is always positive 263 | size_t rest_size = info.size - size; 264 | if (rest_size <= MIN_BLOCK_SIZE) { 265 | // Do not split the block. 266 | remove_block(ptr); 267 | modify_size_info(ptr, info.size, true); 268 | } else { 269 | // Split the block. 270 | word_t *rest = ptr + size / sizeof(char); 271 | modify_size_info(ptr, size, true); 272 | modify_size_info(rest, rest_size, false); 273 | replace(ptr, rest); 274 | if (heap_data->tail == ptr) { 275 | heap_data->tail = rest; 276 | } 277 | } 278 | return ptr + 1; 279 | } 280 | 281 | // the thread is woken up, check whether buffer closed 282 | if (already_closed(buffer)) return CLOSED_ERROR; 283 | } 284 | 285 | /// We separate size and "a" (occupied) from allocator. 286 | static block_info unpack(word_t word) { 287 | block_info info; 288 | info.occupied = word & 1; 289 | info.size = info.occupied ? word - 1:word; 290 | return info; 291 | } 292 | 293 | /* 294 | * mm.c 295 | * 296 | * NAMES: 297 | * 298 | * The whole file is written by , , and . 299 | * The whole project realizes functions such as malloc, free, realloc, calloc, and memalign. 300 | * The project also includes a function to print the heap. 301 | * We debug based on checkpoint files and gdb commands. 302 | * Implementation method: 303 | * + Data structure: implicit list of blocks + explicit free list 304 | + Alignment: 16 bytes, or 2 words 305 | + Coalesces adjacent free blocks 306 | + Check heap function validates the linked list and the consecutive-ness of the blocks 307 | + Malloc splits block if the available block is very large, using a first-fit strategy 308 | */ 309 | 310 | /* sends the JBOD operation to the server (use the send_packet function) and receives 311 | (use the recv_packet function) and processes the response. 312 | 313 | if (already_closed(buffer)) return CLOSED_ERROR; 314 | } 315 | 316 | ///Used for debugging. 317 | static struct { 318 | uint32_t free_block_count; 319 | word_t *head; 320 | word_t *tail; 321 | word_t *first_block; 322 | word_t *last_block; 323 | word_t alloc_unit; 324 | } *heap_data; 325 | 326 | int mdadm_unmount(void) { 327 | monad_apply(from_command(JBOD_UNMOUNT), NULL); 328 | return 1; 329 | } 330 | 331 | #include 332 | #include 333 | #include 334 | 335 | int mdadm_write(uint32_t addr, uint32_t len, const uint8_t *buf) { 336 | // printf("addr = %u, len = %u\n", addr, len); 337 | if (addr < 0 || addr + len > 1048576 || len > 1024) return -1; 338 | if (!len) return len; 339 | if (!buf) return -1; 340 | 341 | // Sorts an array in descending order 342 | void sort(int array[], int length) { 343 | // Bubble sort, using swap I implemented just now :) 344 | int i, j; 345 | for (i = 0; i < length - 1; ++i) 346 | for (j = 0; j < length - i - 1; j++) 347 | if (array[j] < array[j + 1]) 348 | swap(array + j, array + j + 1); 349 | } 350 | 351 | /// Information about a block, see unpack. 352 | typedef struct { 353 | word_t size; 354 | bool occupied; 355 | } block_info; 356 | 357 | #define unpack(cmd) cmd.disk_id, cmd.block_id 358 | void cached_write(const uint8_t *buf, JBOD cmd) { 359 | if (!cache_enabled()) return; 360 | if (cache_insert(unpack(cmd), buf) == -1) 361 | cache_update(unpack(cmd), buf); 362 | } 363 | 364 | // Takes an array of integers and the length of the array as input and double every positive element of the array that is an Armstrong number. 365 | void double_armstrongs(int array[], int length) { 366 | int i; 367 | for (i = 0; i < length; ++i) if (is_arm(array[i])) array[i] = 2 * (array[i]); 368 | } 369 | 370 | int seek(JBOD cmd) { 371 | cmd.command = JBOD_SEEK_TO_DISK; 372 | monad_apply(cmd, NULL); 373 | cmd.command = JBOD_SEEK_TO_BLOCK; 374 | monad_apply(cmd, NULL); 375 | return 0; 376 | } 377 | 378 | /// Given A's pointer, returns the address of the next block. 379 | static word_t *next_block(const word_t *base_addr) { 380 | return *(word_t **) (base_addr + 1); 381 | } 382 | 383 | int inc_block(JBOD *cmd) { 384 | cmd->block_id++; 385 | if (!cmd->block_id) { 386 | cmd->disk_id++; 387 | if (seek(*cmd)) return -1; 388 | } 389 | return 0; 390 | } 391 | 392 | JBOD compute_cmd(uint32_t addr, uint32_t len) { 393 | JBOD cmd; 394 | cmd.disk_id = addr / JBOD_DISK_SIZE; 395 | cmd.block_id = (addr % JBOD_DISK_SIZE) / JBOD_BLOCK_SIZE; 396 | return cmd; 397 | } 398 | 399 | /** 400 | * mm_checkheap 401 | * Validates a heap. 402 | */ 403 | bool mm_checkheap(int lineno) { 404 | if (!heap_data) return true; 405 | return !(check_free_blocks(lineno) || check_heap(lineno)); 406 | } 407 | 408 | /** rounds up to the nearest multiple of ALIGNMENT */ 409 | static size_t align(size_t x) { 410 | return ALIGNMENT * ((x + ALIGNMENT - 1) / ALIGNMENT); 411 | } 412 | 413 | /// Modify the pointer to the next block. 414 | inline static void modify_next(word_t *base_addr, const word_t *pointed_addr) { 415 | *(base_addr + 1) = (word_t) pointed_addr; 416 | } 417 | 418 | // Returns 0 on success 419 | int cached_read(uint8_t *buf, JBOD cmd, bool insert) { 420 | if (cache_lookup(unpack(cmd), buf) == -1) { 421 | // Lookup cache failed 422 | if (seek(cmd)) return -1; 423 | monad_apply(from_command(JBOD_READ_BLOCK), buf); 424 | // If lookup failed, it means a cache miss, we update cache to reflect that 425 | if (insert) cached_write(buf, cmd); 426 | } 427 | return 0; 428 | } 429 | 430 | /* disconnects from the server and resets cli_sd */ 431 | void jbod_disconnect(void) { 432 | close(cli_sd); 433 | cli_sd = -1; 434 | } 435 | 436 | #define apply_data(i, buf) \ 437 | memcpy(cache[i].block, buf, JBOD_BLOCK_SIZE); \ 438 | cache[i].access_time = clock++; \ 439 | cache[i].valid = true; \ 440 | cache[i].disk_num = disk_num; \ 441 | cache[i].block_num = block_num; 442 | 443 | uint8_t cache[JBOD_BLOCK_SIZE]; 444 | uint32_t write_len = len; 445 | while (write_len > 0) { 446 | if (block_offset > 0 || write_len < JBOD_BLOCK_SIZE) { 447 | if (cached_read(cache, cmd, false)) return -1; 448 | if (seek(cmd)) return -1; 449 | } 450 | uint32_t current_write_len = write_len > JBOD_BLOCK_SIZE ? JBOD_BLOCK_SIZE : write_len; 451 | if (block_offset > 0) { 452 | uint32_t max_can_read = JBOD_BLOCK_SIZE - block_offset; 453 | if (max_can_read < current_write_len) current_write_len = max_can_read; 454 | memcpy(cache + block_offset, buf, current_write_len); 455 | block_offset = 0; 456 | } else memcpy(cache, buf, current_write_len); 457 | monad_apply(from_command(JBOD_WRITE_BLOCK), cache); 458 | cached_write(cache, cmd); 459 | buf += current_write_len; 460 | write_len -= current_write_len; 461 | if (inc_block(&cmd)) return -1; 462 | } 463 | return len; 464 | } 465 | 466 | void cache_update(int disk_num, int block_num, const uint8_t *buf) { 467 | cache_entry_t *entry = find_cache(disk_num, block_num); 468 | if (entry) { 469 | memcpy(entry->block, buf, JBOD_BLOCK_SIZE); 470 | entry->access_time = clock++; 471 | } 472 | } 473 | 474 | #include "mm.h" 475 | #include "memlib.h" 476 | 477 | } 478 | 479 | /* the client socket descriptor for the connection to the server */ 480 | int cli_sd = -1; 481 | 482 | /// Check the return value of sbrk 483 | static bool is_sbrk_invalid(void *ptr) { 484 | return ptr == (void *) -1; 485 | } 486 | 487 | return status; 488 | } 489 | 490 | if (already_closed(buffer)) return CLOSED_ERROR; 491 | 492 | /* do not change the following! */ 493 | #ifdef DRIVER 494 | /* create aliases for driver tests */ 495 | #define malloc mm_malloc 496 | #define free mm_free 497 | #define realloc mm_realloc 498 | #define calloc mm_calloc 499 | #define memset mem_memset 500 | #define memcpy mem_memcpy 501 | #endif /* DRIVER */ 502 | 503 | /// As the name suggests :) 504 | /// Assumes: ptr is already in the free list 505 | static word_t *free_and_coalesce(word_t *ptr, word_t size) { 506 | heap_data->free_block_count++; 507 | word_t *ptr_prev = ptr > heap_data->first_block ? ptr - information(ptr - 1).size : NULL; 508 | word_t *ptr_next = ptr < heap_data->last_block ? ptr + size : NULL; 509 | word_t prev_size = release_free_block(ptr_prev); 510 | // What is the size of the coalesced block? 511 | word_t new_size = size + prev_size + release_free_block(ptr_next); 512 | // What is the starting address of the coalesced block? 513 | word_t *base_addr = prev_size > 0 ? ptr_prev : ptr; 514 | if (DEBUG && new_size != size) { 515 | printf("Coalesce: at %p -> %p, size %lu -> %lu\n", ptr, base_addr, size, new_size); 516 | } 517 | // Refresh the size information 518 | modify_size_info(base_addr, new_size, false); 519 | // Add the new block to the head 520 | if (base_addr != heap_data->head) 521 | insert_before(base_addr, heap_data->head); 522 | // The "prev" of the new head is NULL, of course 523 | modify_prev(base_addr, NULL); 524 | return base_addr; 525 | } 526 | 527 | bool already_closed(const state_t *buffer) { 528 | if (!buffer->isopen) { 529 | pthread_mutex_unlock(&buffer->chmutex); 530 | return true; 531 | } 532 | return false; 533 | } 534 | 535 | return BUFFER_SUCCESS; 536 | 537 | /* Lab- 1 Due by 11th Feb 2022 538 | Make sure your code looks clean 539 | Write comments with your code 540 | Do not foget to 'push' your code github reglarly 541 | */ 542 | 543 | JBOD cmd = compute_cmd(addr, len); 544 | uint32_t block_offset = addr % JBOD_BLOCK_SIZE; 545 | if (seek(cmd)) return -1; 546 | 547 | int cache_destroy(void) { 548 | if (!cache) return -1; 549 | free(cache); 550 | cache = NULL; 551 | cache_size = 0; 552 | return 1; 553 | } 554 | 555 | // Takes an array of integers and the length of the array as input, and returns the sum of the integers in the array. 556 | int sum(int array[], int length) { 557 | // Straightforward logic 558 | int all = 0, i; 559 | for (i = 0; i < length; ++i) all += array[i]; 560 | return all; 561 | } 562 | 563 | bool cache_enabled(void) { 564 | return cache_size >= 2; 565 | } 566 | 567 | #include "buffer.h" 568 | 569 | /** 570 | * free 571 | */ 572 | void free(void *ptr) { 573 | word_t *base_addr = ((word_t *) ptr) - 1; 574 | block_info info = information(base_addr); 575 | if (DEBUG) printf("Free: base_addr = %p, size = %zu, occ = %i\n", base_addr, info.size, info.occupied); 576 | free_and_coalesce(base_addr, info.size); 577 | } 578 | 579 | int mdadm_mount(void) { 580 | monad_apply(from_command(JBOD_MOUNT), NULL); 581 | return 1; 582 | } 583 | 584 | // const size_t LARGE_UNIT = 2048; 585 | /// In case size==0, we grow by a default size. 586 | /// Assume the unit of size is word. 587 | static word_t *grow_heap(size_t words) { 588 | // If the last block is free, we may request a 589 | // smaller block and coalease to get an appropriate block 590 | if (heap_data->last_block) { 591 | block_info info = information(heap_data->last_block); 592 | if (!info.occupied && info.size < words) { 593 | words -= info.size; 594 | } 595 | } 596 | // How many bytes to sbrk when the heapsize is not enough? 597 | if (words <= heap_data->alloc_unit) words = heap_data->alloc_unit; 598 | // if (heap_data->alloc_unit == (1 << 15)) heap_data->alloc_unit = 1 << 14; 599 | // else if (words <= LARGE_UNIT) words = LARGE_UNIT; 600 | // else: words = words 601 | if (DEBUG) printf("Grow: words = %zu\n", words); 602 | word_t *ptr = mem_sbrk((intptr_t) (words * sizeof(word_t))); 603 | if (is_sbrk_invalid(ptr)) return NULL; 604 | heap_data->last_block = ptr; 605 | return free_and_coalesce(ptr, words); 606 | } 607 | 608 | pthread_mutex_unlock(&buffer->chmutex); 609 | 610 | static cache_entry_t *cache = NULL; 611 | static int cache_size = 0; 612 | static int clock = 0; 613 | static int num_queries = 0; 614 | static int num_hits = 0; 615 | 616 | #endif 617 | 618 | 619 | /* attempts to connect to server and set the global cli_sd variable to the 620 | * socket; returns true if successful and false if not. 621 | * this function will be invoked by tester to connect to the server at given ip and port. 622 | * you will not call it in mdadm.c 623 | */ 624 | bool jbod_connect(const char *ip, uint16_t port) { 625 | cli_sd = socket(AF_INET, SOCK_STREAM, 0); 626 | if (cli_sd < 0) return false; 627 | struct sockaddr_in serv_addr; 628 | serv_addr.sin_family = AF_INET; 629 | serv_addr.sin_port = htons(port); 630 | if (!inet_aton(ip, &serv_addr.sin_addr)) 631 | return false; 632 | return !connect(cli_sd, (const struct sockaddr *) &serv_addr, sizeof(serv_addr)); 633 | } 634 | 635 | /// Prints a heap. 636 | void print_free_blocks(int lineno) { 637 | printf("Check: at line %i ==============\n", lineno); 638 | for (word_t *node = heap_data->head; node;) { 639 | block_info info = information(node); 640 | printf("Node at: %p, size = %7lu, occ = %i", node, info.size, info.occupied); 641 | if (!info.occupied) { 642 | word_t *next = next_block(node); 643 | printf(", next = %p, prev = %p\n", next, prev_block(node)); 644 | if (next && next != node) node = next; 645 | else break; 646 | } else { 647 | puts(""); 648 | break; 649 | } 650 | } 651 | printf("Heap tail: %p\n", heap_data->tail); 652 | } 653 | 654 | // Takes pointers to two integers and swaps the values of integers 655 | void swap(int *a, int *b) { 656 | // The obvious implementation 657 | int t = *a; 658 | *a = *b; 659 | *b = t; 660 | } 661 | 662 | // 663 | // @psu.edu 664 | 665 | /// Returns the address of the previous block. 666 | static word_t *prev_block(const word_t *base_addr) { 667 | return *(word_t **) (base_addr + 2); 668 | } 669 | 670 | #include 671 | #include 672 | #include 673 | #include 674 | #include 675 | #include 676 | #include 677 | 678 | /** What is the correct alignment? */ 679 | const size_t ALIGNMENT = 16; 680 | typedef uint64_t word_t; 681 | /// Size of two words, at the beginning and the end of the block. 682 | const size_t INFO_SIZE = 2; 683 | /// Size of an empty block. 684 | const size_t MIN_BLOCK_SIZE = 4; 685 | const bool DEBUG = false; 686 | 687 | int cache_insert(int disk_num, int block_num, const uint8_t *buf) { 688 | if (invalid_state(disk_num, block_num, buf)) return -1; 689 | int index = 0; 690 | int oldest_clock = clock; 691 | for_caches(i) { 692 | if (block_matches(i)) { 693 | // Found an existing cache 694 | return -1; 695 | } else if (!cache[i].valid) { 696 | // Still have space for new caches 697 | apply_data(i, buf); 698 | return 1; 699 | } else { 700 | int new_clock = cache[i].access_time; 701 | if (new_clock < oldest_clock) { 702 | index = i; 703 | oldest_clock = new_clock; 704 | } 705 | } 706 | } 707 | // Overwrite an old cache 708 | apply_data(index, buf); 709 | return 1; 710 | } 711 | 712 | #include 713 | #include 714 | #include 715 | 716 | // Closes the buffer and informs all the blocking send/receive/select calls to return with CLOSED_ERROR 717 | // Once the buffer is closed, send/receive/select operations will cease to function and just return CLOSED_ERROR 718 | // Returns BUFFER_SUCCESS if close is successful, 719 | // CLOSED_ERROR if the buffer is already closed, and 720 | // BUFFER_ERROR in any other error case 721 | enum buffer_status buffer_close(state_t *buffer) { 722 | 723 | // receive messages 724 | if (BUFFER_SUCCESS == (status = buffer_remove_Q(buffer, data))) { 725 | // check whether is special message 726 | if (strcmp((const char *) data, "splmsg") == 0) { 727 | puts("Special message. What?"); 728 | status = BUFFER_SPECIAL_MESSSAGE; 729 | } 730 | 731 | The meaning of each parameter is the same as in the original jbod_operation function. 732 | return: 0 means success, -1 means failure. 733 | */ 734 | #define BOKI_WRITE(msg) write(cli_sd, &msg, sizeof(msg)) 735 | #define BOKI_READ(msg) if (read(cli_sd, &msg, sizeof(msg)) <= 0) return -1; 736 | int jbod_client_operation(uint32_t op, uint8_t *block) { 737 | uint16_t length; 738 | op = htonl(op); 739 | uint16_t ret_code = htons(0); 740 | if (block) { // block != NULL 741 | length = htons(HEADER_LEN + JBOD_BLOCK_SIZE); 742 | BOKI_WRITE(length); 743 | BOKI_WRITE(op); 744 | BOKI_WRITE(ret_code); 745 | write(cli_sd, block, JBOD_BLOCK_SIZE); 746 | } else { 747 | length = htons(HEADER_LEN); 748 | BOKI_WRITE(length); 749 | BOKI_WRITE(op); 750 | BOKI_WRITE(ret_code); 751 | } 752 | BOKI_READ(length); 753 | BOKI_READ(op); 754 | BOKI_READ(ret_code); 755 | length = ntohs(length); 756 | ret_code = ntohs(ret_code); 757 | if (length > HEADER_LEN) { 758 | // printf("Len = %u\n", length); 759 | read(cli_sd, block, JBOD_BLOCK_SIZE); 760 | } 761 | return 0; 762 | } 763 | 764 | 765 | /// A reconstruction of uint32_t that fits our need 766 | typedef struct { 767 | uint32_t block_id : 8; 768 | uint32_t reserved : 14; 769 | uint32_t disk_id : 4; 770 | jbod_cmd_t command : 6; 771 | } JBOD; 772 | 773 | #include "mdadm.h" 774 | #include "jbod.h" 775 | #include "net.h" 776 | 777 | /// Remove the block from linked list when necessary 778 | /// Returns: the released block size, 779 | /// positive if ptr != null and it is free 780 | /// 0 if ptr == null or it is occupied 781 | static word_t release_free_block(word_t *ptr) { 782 | if (!ptr) return 0; 783 | block_info info = information(ptr); 784 | if (!info.occupied) { 785 | remove_block(ptr); 786 | return info.size; 787 | } 788 | return 0; 789 | } 790 | 791 | // Writes data to the given buffer 792 | // This is a blocking call i.e., the function only returns on a successful completion of send 793 | // In case the buffer is full, the function waits till the buffer has space to write the new data 794 | // Returns BUFFER_SUCCESS for successfully writing data to the buffer, 795 | // CLOSED_ERROR if the buffer is closed, and 796 | // BUFFER_ERROR on encountering any other generic error of any sort 797 | enum buffer_status buffer_send(state_t *buffer, void *data) { 798 | enum buffer_status status; 799 | pthread_mutex_lock(&buffer->chmutex); 800 | 801 | // Power helpers 802 | int sq(int i) { return i * i; } 803 | int cb(int i) { return i * i * i; } 804 | int pwr(int n, int i) { return i ? n * pwr(n, i - 1) : 1; } 805 | 806 | #define for_caches(i) \ 807 | int i; \ 808 | for (i = 0; i < cache_size; ++i) 809 | #define block_matches(i) \ 810 | cache[i].valid && cache[i].block_num == block_num &&cache[i].disk_num == disk_num 811 | 812 | /** 813 | * Returns whether the pointer is in the heap. 814 | * May be useful for debugging. 815 | */ 816 | static bool in_heap(const void *p) { 817 | return p <= mem_heap_hi() && p >= mem_heap_lo(); 818 | } 819 | 820 | int cache_lookup(int disk_num, int block_num, uint8_t *buf) { 821 | if (invalid_state(disk_num, block_num, buf)) return -1; 822 | num_queries++; 823 | cache_entry_t *entry = find_cache(disk_num, block_num); 824 | if (entry) { 825 | memcpy(buf, entry->block, JBOD_BLOCK_SIZE); 826 | entry->access_time = clock++; 827 | num_hits++; 828 | return 1; 829 | } else 830 | return -1; 831 | } 832 | 833 | // Creates a buffer with the given capacity 834 | state_t *buffer_create(int capacity) { 835 | state_t *buffer = (state_t *) malloc(sizeof(state_t)); 836 | buffer->fifoQ = (fifo_t *) malloc(sizeof(fifo_t)); 837 | fifo_init(buffer->fifoQ, capacity); 838 | buffer->isopen = true; 839 | if (pthread_mutex_init(&buffer->chclose, NULL) 840 | && pthread_cond_init(&buffer->chconsend, NULL) 841 | && pthread_mutex_init(&buffer->chmutex, NULL) 842 | && pthread_cond_init(&buffer->chconrec, NULL) != 0) { 843 | puts("Failed to initialize buffer"); 844 | // Don't expect this to happen 845 | } 846 | return buffer; 847 | } 848 | 849 | // wake up all threads and close them 850 | run_both(pthread_cond_broadcast, &buffer->chconsend, &buffer->chconrec); 851 | run_both(pthread_mutex_unlock, &buffer->chmutex, &buffer->chclose); 852 | 853 | /// A monadic syntax for applying a command 854 | #define monad_apply(cmd, buf) { if (apply_cmd(cmd, buf)) return -1; } 855 | 856 | // Rotate values of integers 857 | void rotate(int *a, int *b, int *c) { 858 | // What else can I do 859 | swap(a, b); 860 | swap(a, c); 861 | } 862 | 863 | pthread_cond_signal(&buffer->chconsend); 864 | } 865 | 866 | pthread_mutex_lock(&buffer->chmutex); 867 | 868 | return status; 869 | } 870 | // test_send_correctness 1 871 | // Reads data from the given buffer and stores it in the function’s input parameter, data (Note that it is a double pointer). 872 | // This is a blocking call i.e., the function only returns on a successful completion of receive 873 | // In case the buffer is empty, the function waits till the buffer has some data to read 874 | // Return BUFFER_SPECIAL_MESSSAGE for successful retrieval of special data "splmsg" 875 | // Returns BUFFER_SUCCESS for successful retrieval of any data other than "splmsg" 876 | // CLOSED_ERROR if the buffer is closed, and 877 | // BUFFER_ERROR on encountering any other generic error of any sort 878 | 879 | int cache_create(int num_entries) { 880 | if (cache || num_entries < 2 || num_entries > 4096) return -1; 881 | size_t size = sizeof(cache_entry_t) * num_entries; 882 | cache = malloc(size); 883 | memset(cache, 0, size); 884 | cache_size = num_entries; 885 | clock = 0; 886 | return 1; 887 | } 888 | 889 | /// Replace base_addr with new_addr in the free list. 890 | static void replace(const word_t *base_addr, word_t *new_addr) { 891 | word_t *ptr_prev = prev_block(base_addr); 892 | word_t *ptr_next = next_block(base_addr); 893 | // Reconnect 894 | insert(new_addr, ptr_prev, ptr_next); 895 | } 896 | 897 | int is_arm(int n) { 898 | if (n <= 0) return 0; 899 | int all = 0, m = n, pw = 0; 900 | // Calculate pw: the number of digits in n 901 | while (m) { ++pw; m /= 10; } 902 | m = n; 903 | while (n > 0) { 904 | // Sum up 905 | all += pwr(n % 10, pw); 906 | n /= 10; 907 | } 908 | // Is it armstrong? 909 | return all == m; 910 | } 911 | 912 | cache_entry_t *find_cache(int disk_num, int block_num) { 913 | for_caches(i) { 914 | if (block_matches(i)) 915 | return &cache[i]; 916 | } 917 | return NULL; 918 | } 919 | 920 | #include 921 | #include 922 | #include 923 | #include 924 | #include 925 | #include 926 | #include 927 | #include 928 | #include 929 | #include 930 | #include "net.h" 931 | #include "jbod.h" 932 | // #include 933 | // static_assert(sizeof(MsgHead) == HEADER_LEN); 934 | 935 | //Takes an array of integers and the length of the array as input and cubes every prime element of the array 936 | void cube_primes(int array[], int length) { 937 | int i; 938 | for (i = 0; i < length; ++i) if (is_prime(array[i])) array[i] = cb(array[i]); 939 | } 940 | 941 | /** 942 | * calloc 943 | * This function is not tested by mdriver, and has been implemented for you. 944 | */ 945 | void *calloc(size_t nmemb, size_t size) { 946 | void *ptr; 947 | size *= nmemb; 948 | ptr = malloc(size); 949 | if (ptr) { 950 | memset(ptr, 0, size); 951 | } 952 | return ptr; 953 | } 954 | 955 | /// Modify the size information of a block. 956 | static void modify_size_info(word_t *base_addr, word_t size, bool occupied) { 957 | word_t packed_data = size | (occupied ? 1:0); 958 | *base_addr = packed_data; 959 | *(base_addr + size - 1) = packed_data; 960 | } 961 | 962 | #ifndef __JBOD_STRUCT_ONLY__ 963 | 964 | int is_happy(int n) { 965 | // Reference: https://en.wikipedia.org/wiki/Happy_number#10-happy_numbers 966 | if (n < 10) return n == 1 || n == 7; 967 | // For one digit numbers, only 1 and 7 are happy 968 | int all = 0; 969 | while (n > 0) { 970 | all += sq(n % 10); 971 | n /= 10; 972 | } 973 | // Recursively test until n < 10 974 | return is_happy(all); 975 | } 976 | 977 | #include "student.h" 978 | #include 979 | 980 | //Take an array of integers and length of the arrays as input and negate every happy number of that array 981 | void negate_happy(int array[], int length) { 982 | int i; 983 | for (i = 0; i < length; ++i) if (is_happy(array[i])) array[i] = -(array[i]); 984 | } 985 | 986 | 987 | /// The most complex logic 988 | int mdadm_read(uint32_t addr, uint32_t len, uint8_t *buf) { 989 | if (addr < 0 || addr + len > 1048576 || len > 1024) return -1; 990 | if (!len) return len; 991 | if (!buf) return -1; 992 | 993 | /// Validate the implicit linked list of all blocks. 994 | /// Returns true if there is an error. 995 | bool check_heap(int lineno) { 996 | bool has_error = false; 997 | for (word_t *node = heap_data->first_block; in_heap(node);) { 998 | block_info info = information(node); 999 | block_info end_info = unpack(*(node + info.size - 1)); 1000 | if (info.size != end_info.size || info.occupied != end_info.occupied) { 1001 | has_error = true; 1002 | printf("Check: boundary information mismatch for block %p\n" 1003 | " head: %lu - %i, tail: %lu - %i\n", node, 1004 | info.size, info.occupied, end_info.size, end_info.occupied); 1005 | break; 1006 | } 1007 | // TODO: more checking 1008 | node += info.size; 1009 | } 1010 | if (has_error) print_free_blocks(lineno); 1011 | // else puts("Check heap: no error found"); 1012 | return has_error; 1013 | } 1014 | 1015 | /// Validate the linked list of free blocks. 1016 | /// Returns true if there is an error. 1017 | bool check_free_blocks(int lineno) { 1018 | bool has_error = false; 1019 | if (!heap_data->head) { 1020 | if (DEBUG) printf("Check: head is null\n"); 1021 | } else for (word_t *node = heap_data->head;;) { 1022 | // if (!aligned(node)) has_error = true; 1023 | block_info info = information(node); 1024 | if (info.occupied) { 1025 | printf("Check: occupied block at %p\n", node); 1026 | has_error = true; 1027 | break; 1028 | } else { 1029 | word_t *next = next_block(node); 1030 | if (next == node) { 1031 | has_error = true; 1032 | printf("Check: recursive block %p\n", node); 1033 | break; 1034 | } 1035 | if (next) { 1036 | if (prev_block(next) != node) { 1037 | has_error = true; 1038 | printf("Check: linked list broken at %p\n", node); 1039 | break; 1040 | } 1041 | node = next; 1042 | } else { 1043 | if (heap_data->tail != node) { 1044 | has_error = true; 1045 | printf("Check: tail and last element doesn't match\n"); 1046 | } 1047 | break; 1048 | } 1049 | } 1050 | } 1051 | if (has_error) print_free_blocks(lineno); 1052 | // else puts("Check free list: no error found"); 1053 | return has_error; 1054 | } 1055 | 1056 | enum buffer_status buffer_destroy(state_t *buffer) { 1057 | if (buffer->isopen) { 1058 | return DESTROY_ERROR; 1059 | } 1060 | if (run_both(pthread_mutex_destroy, &buffer->chclose, &buffer->chmutex) 1061 | && run_both(pthread_cond_destroy, &buffer->chconsend, &buffer->chconrec) 1062 | != 0) 1063 | puts("Failed to destroy buffer"); 1064 | fifo_free(buffer->fifoQ); 1065 | free(buffer); 1066 | return BUFFER_SUCCESS; 1067 | } 1068 | --------------------------------------------------------------------------------