Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Adding in updates.

Need a bit more text, but most everything is documented at this point.
  • Loading branch information...
commit 730bb3eaea1fb98e0ae3c5795205d95d0faec1f1 1 parent 7c3203c
@jadudm authored
View
25 asm/asm-support.rkt
@@ -60,6 +60,31 @@
newsym))))
;; CONTRACT
+;; pad :: string number -> string
+;; PURPOSE
+;; Pads a string with leading zeros.
+(define (pad str ln)
+ (string-append (make-string
+ (- ln (string-length str))
+ #\0) str))
+
+;; CONTRACT
+;; number->15bit :: number -> string
+;; PURPOSE
+;; Converts a number to a binary string,
+;; making sure the number is less than 2^15.
+(define (number->15bit v)
+ (if (< v (expt 2 15))
+ (let ([n (number->string v 2)])
+ (if (< (string-length n) 15)
+ (pad n 15)
+ n))
+ (error (format "~a is not less than ~a."
+ v
+ (expt 2 15)))))
+
+
+;; CONTRACT
;; extract-comp :: string -> symbol
;; PURPOSE
;; Takes an instruction of the form
View
12 asm/driver.rkt
@@ -29,16 +29,16 @@
[parsed (parse list-of-strings)]
;; Now, attach instruction locations
[numbered (attach-instruction-locations parsed 0)]
+ ;; Init table
+ [x (init-symbol-table)]
;; Add labels
[x1 (add-labels-to-table numbered)]
;; Add memory locations
- [x2 (add-memory-addresses-to-table numbered)]
- ;; Assign the addresses
- [assigned (assign-addresses numbered)]
- ;; Filter out the labels that remain
- [no-labels (filter (λ (i) (not (label? i))) assigned)]
+ [assigned (add-memory-addresses-to-table numbered)]
+ ;; Assign addresses to everything
+ [no-labels (rewrite-with-addresses assigned)]
;; Convert structures to binary
[zeroones (map structure->binary no-labels)]
;; Write the file
- [x3 (write-file! file res)]
+ [x3 (write-file! file zeroones)]
[final numbered]))
View
73 asm/pass-add-to-table.rkt
@@ -0,0 +1,73 @@
+#lang racket
+
+(provide
+ init-symbol-table
+ add-labels-to-table
+ add-memory-addresses-to-table)
+
+
+;; We will use a hash table to store the
+;; symbols and their memory locations as
+;; key-value pairs. The symbol will be the
+;; key, and the value will be its location in memory.
+(define SYMBOL-TABLE (make-hash))
+
+;; CONTRACT
+;; get-table
+;; PURPOSE
+;; Gets the symbol table.
+(define (get-table)
+ SYMBOL-TABLE)
+
+;; CONTRACT
+;; in-table? :: key -> boolean
+;; PURPOSE
+;; Returns true if the key is in the table.
+(define (in-table? key)
+ (hash-ref SYMBOL-TABLE key (λ () false)))
+
+;; CONTRACT
+;; lookup :: key -> number
+;; PURPOSE
+;; Returns the memory address associated with
+;; the given key.
+(define (lookup key)
+ (hash-ref SYMBOL-TABLE key
+ (λ ()
+ (error (format "~a not in symbol table." key)))))
+
+;; CONTRACT
+;; insert :: key number -> number
+;; PURPOSE
+;; Inserts a key and address into the table.
+;; Returns the value inserted.
+(define (insert key addr)
+ (hash-set! SYMBOL-TABLE key addr)
+ addr)
+
+;; CONTRACT
+;; init-symbol-table
+;; PURPOSE
+;; Loads default symbols into the table.
+(define (init-symbol-table)
+ (map (λ (pair)
+ (insert (first pair) (second pair)))
+ `((SP 0) (LCL 1) (ARG 2) (THIS 3) (THAT 4)
+ ,@(map (λ (n)
+ (list (string->symbol (format "R~a" n)) n))
+ (list 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15))
+ (SCREEN 16384) (KBD 24576))))
+
+;; CONTRACT
+;; add-labels-to-table :: (list-of instructions) number -> (list-of instructions)
+;; PURPOSE
+;; Takes a list of instructions and adds each label to the table.
+(define (add-labels-to-table loi addr)
+ '...)
+
+;; CONTRACT
+;; add-memory-addresses-to-table :: (list-of instructions) number -> (list-of add-memory-addresses-to-table)
+;; PURPOSE
+;; Takes a list of instructions and adds each memory address to the table.
+(define (add-memory-addresses-to-table loi addr)
+ '...)
View
35 asm/pass-symbol-table.rkt
@@ -3,9 +3,9 @@
(require "asm-base.rkt"
"asm-support.rkt")
-(provide add-labels-to-table
+(provide init-symbol-table
+ add-labels-to-table
add-memory-addresses-to-table
- assign-addresses
)
;; Originally, the assembler was written in a purely
@@ -17,6 +17,19 @@
(define SYMBOL-TABLE (make-hash))
;; CONTRACT
+;; init-symbol-table
+;; PURPOSE
+;; Loads default symbols into the table.
+(define (init-symbol-table)
+ (map (λ (pair)
+ (table-add! (first pair) (second pair)))
+ `((SP 0) (LCL 1) (ARG 2) (THIS 3) (THAT 4)
+ ,@(map (λ (n)
+ (list (string->symbol (format "R~a" n)) n))
+ (list 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15))
+ (SCREEN 16384) (KBD 24576))))
+
+;; CONTRACT
;; table-add! :: symbol number -> void
;; PURPOSE
;; Adds a new label or memory address to the table.
@@ -84,17 +97,9 @@
))
;; CONTRACT
-;; assign-addresses :: (list-of instructions) -> (list-of instructions)
+;; rewrite-with-addresses :: (list-of instructions) -> (list-of instructions)
;; PURPOSE
-;; This pass walks through each instruction, rewriting it as we go.
-;; If we find a symbol A instruction, we should replace the symbolic
-;; value with the numberic value stored in the symbol table.
-;; Otherwise, we should keep the instruction as-is.
-(define (assign-addresses loi)
- (cond
- [(empty? loi) '()]
- ;; ...
- [else
- (cons (first loi)
- (assign-addresses (rest loi) ))]
- ))
+;; Takes a list of instructions and rewrites the instruction stream
+;; so that no symbolic references remain.
+(define (rewrite-with-addresses loi)
+ '...)
View
99 asm/pass-to-binary.rkt
@@ -5,5 +5,104 @@
(provide structure->binary)
+;; HELPERS
+;; These functions all take a symbol
+;; representing an instruction and return the binary
+;; string representing that instruction. These values are
+;; extracted from Elements of Computing Systems by
+;; Noam Nisan and Shimon Schocken
+
+;; CONTRACT
+;; a-bits :: instruction -> string
+;; PURPOSE
+;; Takes an instruction and returns the "a" bit.
+;; This is either a zero or a one.
+(define (a-bit inst)
+ (cond
+ [(member (C-comp inst)
+ '(0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D\|A))
+ "0"]
+ [else
+ "1"]))
+
+;; CONTRACT
+;; c-bits :: instruction -> string
+;; PURPOSE
+;; Takes an instruction and returns the "c" bits.
+;; These control the accumulator, and are all of
+;; length six.
+(define (c-bits inst)
+ (case (C-comp inst)
+ ((0) "101010")
+ ((1) "111111")
+ ((-1) "111010")
+ ((D) "001100")
+ ((A) "110000")
+ ((!D) "001101")
+ ((!A) "110001")
+ ((-D) "001111")
+ ((-A) "110011")
+ ((D+1) "011111")
+ ((A+1) "110111")
+ ((D-1) "001110")
+ ((A-1) "110010")
+ ((D+A) "000010")
+ ((D-A) "010011")
+ ((A-D) "000111")
+ ((D&A) "000000")
+ ((D\|A) "010101")
+ ((M) "110000")
+ ((!M) "110001")
+ ((-M) "110011")
+ ((M+1) "110111")
+ ((M-1) "110010")
+ ((D+M) "000010")
+ ((D-M) "010011")
+ ((M-D) "000111")
+ ((D&M) "000000")
+ ((D\|M) "010101")))
+
+;; CONTRACT
+;; d-bits :: instruction -> string
+;; PURPOSE
+;; Returns the "d" bits, given an instruction.
+;; These are all the destinations of the operation
+;; of the accumulator, and are of length 3.
+(define (d-bits inst)
+ (match (C-dest inst)
+ ['no-dest "000"]
+ ['M "001"]
+ ['D "010"]
+ ['MD "011"]
+ ['A "100"]
+ ['AM "101"]
+ ['AD "110"]
+ ['AMD "111"]))
+
+;; CONTRACT
+;; j-bits :: instruction -> string
+;; PURPOSE
+;; Returns the "j" bits, which control
+;; where we go next. These are of length 3, and
+;; primarily control the program counter.
+(define (j-bits inst)
+ (match (C-jump inst)
+ ['no-jump "000"]
+ ['JGT "001"]
+ ['JEQ "010"]
+ ['JGE "011"]
+ ['JLT "100"]
+ ['JNE "101"]
+ ['JLE "110"]
+ ['JMP "111"]))
+
+;; CONTRACT
+;; structure->binary :: instruction -> string
+;; PURPOSE
+;; Takes an instruction (either a C or an A instruction) and
+;; returns the 16 bit binary string that represents the machine
+;; code instruction for the AST representation that you are given.
+;; HINT
+;; Should probably use string-append and the functions above.
(define (structure->binary ast)
'...)
View
17 asm/pass-write-file.rkt
@@ -5,5 +5,18 @@
(provide write-file!)
-(define (write-file! lobin file)
- '...)
+;; CONTRACT
+;; write-file! :: filename (list-of strings) -> void
+;; PURPOSE
+;; Takes the original filename and a list of strings
+;; representing the machine code for a program, and
+;; writes each string to the file. It does overwrite
+;; existing files, but hopefully nothing in the user's directory will
+;; have the extention "hack".
+(define (write-file! orig-file binary)
+ (let* ([outfile (regexp-replace ".asm$" orig-file "-dr.hack")]
+ [op (open-output-file outfile #:exists 'replace)])
+ (for-each (λ (s)
+ (fprintf op "~a~n" s))
+ binary)
+ (close-output-port op)))
View
3  docu/assembler.scrbl
@@ -13,4 +13,5 @@
@include-section["structures.scrbl"]
@include-section["read-file.scrbl"]
@include-section["parse.scrbl"]
-@include-section["attach.scrbl"]
+@include-section["attach.scrbl"]
+@include-section["table.scrbl"]
View
193 docu/table.scrbl
@@ -0,0 +1,193 @@
+#lang scribble/doc
+@(require
+ scribble/core
+ scribble/manual
+ scribble/bnf
+ "about-the-assembler.rkt")
+
+@title[#:tag "table"]{Pass: Populating the symbol table}
+
+The symbol table is where all of the magic in our assembler happens. It takes all of the variables
+(symbols) in our instruction stream, and replaces them with actual memory addresses. For example,
+if we have a piece of code like the following:
+
+@verbatim|{
+ @5
+ D=A
+ @i
+ M=D
+ (INIFITE_LOOP)
+ @INFINITE_LOOP
+ 0;JMP
+ }|
+
+the assembler will go through and replace all of the symbols with addresses in RAM:
+
+@verbatim|{
+ @5
+ D=A
+ @16
+ M=D
+ @4
+ 0;JMP
+ }|
+
+The symbol @tt{i} was given the address @tt{16}, and the label @tt{INFINITE_LOOP} was given the
+address @tt{4}. The assignment of addresses takes place in the pass @tt{add-memory-addresses-to-table},
+and the assignemnt of label locations takes place in the pass @tt{add-labels-to-table}.
+
+
+@section{@tt{add-labels-to-table}}
+
+Each label has a location in the instruction stream. Whenever an @tt{A} instruction refers
+to a label, we need to replace that label reference with the address of the label.
+
+To do this, we first have to go through and insert each label into the symbol table. For example,
+consider the following block of assembly (similar to the one from the previous section):
+
+@(racketblock
+ (list
+ (label 0 'label0)
+ (C 0 'D1 'C2 'J3)
+ (A 1 0)
+ (label 2 'label4)
+ (label 2 'label5)
+ (label 2 'label6)
+ (label 2 'label7)
+ (label 2 'label8)
+ (C 2 'D9 'C10 'J11)
+ (C 3 'D12 'C13 'J14)
+ (A 4 'next)
+ (C 5 'D15 'C16 'J17)
+ (C 6 'D18 'C19 'J20)
+ (A 7 'label5)
+ (C 8 'D21 'C22 'J23)
+ (A 9 22)
+ (C 10 'D24 'C25 'J26)))
+
+There are six labels: @tt{label0}, @tt{label4}, @tt{label5}, @tt{label6}, @tt{label7}, and @tt{label8}.
+Each of these carry with them their current address in ROM. For example, @tt{label0} is pointing to
+address zero in ROM, and hence its address field is correct (from previous passes). We need to
+find each label instruction and insert the label name and ROM address into the table.
+
+When we are done, the symbol table should look like this
+
+@verbatim|{
+ #hash((label0 0)
+ (label4 2)
+ (label5 2)
+ (label6 2)
+ (label7 2)
+ (label8 2)
+ )}|
+
+@section{@tt{add-memory-addresses-to-table}}
+
+Assume we have a list of instructions like the following:
+
+@(racketblock
+ (list
+ (label 0 'label0)
+ (C 0 'D1 'C2 'J3)
+ (A 1 0)
+ (label 2 'label4)
+ (label 2 'label5)
+ (label 2 'label6)
+ (label 2 'label7)
+ (label 2 'label8)
+ (C 2 'D9 'C10 'J11)
+ (C 3 'D12 'C13 'J14)
+ (A 4 'next)
+ (C 5 'D15 'C16 'J17)
+ (C 6 'D18 'C19 'J20)
+ (A 7 'label5)
+ (C 8 'D21 'C22 'J23)
+ (A 9 22)
+ (C 10 'D24 'C25 'J26)))
+
+There are an assortment of @tt{labels}, @tt{C} instructions, and @tt{A} instructions.
+There is one symbolic @tt{A} instruction in this stream: @(racket (A 4 'next)).
+When we find the symbolic reference, we should insert it into the symbol table.
+By default, we start numbering symbolic references at memory address 16; this way,
+we do not interfere with the locations of registers R0 through R15 (which live at
+locations 0 through 15).
+
+After running the pass @tt{add-memory-addresses-to-table}, we should end up
+with the same instruction stream, but the symbol table should look like this:
+
+@verbatim|{
+ #hash((label0 0)
+ (label4 2)
+ (label5 2)
+ (label6 2)
+ (label7 2)
+ (label8 2)
+ (next 16)
+ )}|
+
+The ordering in the symbol table does not matter; we are not guaranteed
+any particular order when we use a hash table in this way. However, we should
+still have all of the label addresses and, when we're done with this pass,
+all of the symbolic references should be assigned addresses as well.
+
+When we're done, we should still have the same instruction stream that we
+started with. The next pass will go through the stream, removing instructions,
+and inserting actual values for addresses as appropriate.
+
+@section{@tt{rewrite-with-addresses}}
+
+Before writing out the contents of the assembly, we rewrite the instruction stream
+using the addresses we have inserted into the instruction table.
+
+@(itemize
+ @item{If we encounter a label, we should simply ignore it. Or, if you prefer, it should
+ be removed from the instruction stream. We no longer need the label
+ instructions.}
+ @item{If we find a symbolic @tt{A} instruction, we should look it up in the symbol table, and
+ replace the symbolic form with an actual memory address.}
+ @item{Any other instruction should be left as-is.})
+
+Our example stream from the previous section currently looks like this:
+
+
+@(racketblock
+ (list
+ (label 0 'label0)
+ (C 0 'D1 'C2 'J3)
+ (A 1 0)
+ (label 2 'label4)
+ (label 2 'label5)
+ (label 2 'label6)
+ (label 2 'label7)
+ (label 2 'label8)
+ (C 2 'D9 'C10 'J11)
+ (C 3 'D12 'C13 'J14)
+ (A 4 'next)
+ (C 5 'D15 'C16 'J17)
+ (C 6 'D18 'C19 'J20)
+ (A 7 'label5)
+ (C 8 'D21 'C22 'J23)
+ (A 9 22)
+ (C 10 'D24 'C25 'J26)))
+
+When we are done with the pass @tt{rewrite-with-addresses}, it should look like this:
+
+
+@(racketblock
+ (list
+ (C 0 'D1 'C2 'J3)
+ (A 1 0)
+ (C 2 'D9 'C10 'J11)
+ (C 3 'D12 'C13 'J14)
+ (A 4 16)
+ (C 5 'D15 'C16 'J17)
+ (C 6 'D18 'C19 'J20)
+ (A 7 2)
+ (C 8 'D21 'C22 'J23)
+ (A 9 22)
+ (C 10 'D24 'C25 'J26)))
+
+At this point, labels have been removed, the reference to @tt{label5} has been resolved to ROM location 2, and
+the reference to the symbol @tt{next} has been resolved to RAM address 16.
+
+We are now ready to emit binary machine code.
Please sign in to comment.
Something went wrong with that request. Please try again.