diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | README | 36 | ||||
-rw-r--r-- | asm/Makefile | 10 | ||||
-rw-r--r-- | asm/_tags | 2 | ||||
-rw-r--r-- | asm/asm.ml | 2 | ||||
-rw-r--r-- | asm/asmlex.mll | 11 | ||||
-rw-r--r-- | asm/asmpars.mly | 18 | ||||
-rw-r--r-- | asm/assembler.ml | 8 | ||||
-rw-r--r-- | cpu/Makefile | 8 | ||||
-rw-r--r-- | cpu/ROM_count_seconds.rom (renamed from cpu/prog_rom0.rom) | 0 | ||||
-rw-r--r-- | cpu/alu.ml | 148 | ||||
-rw-r--r-- | cpu/cpu.ml | 41 | ||||
-rw-r--r-- | cpu/netlist_gen.ml | 70 | ||||
-rw-r--r-- | cpu/netlist_gen.mli | 2 | ||||
-rw-r--r-- | cpu/netlist_printer.ml | 82 | ||||
-rw-r--r-- | cpu/os.asm | 259 | ||||
-rw-r--r-- | csim/sim.c | 9 | ||||
-rw-r--r-- | monitor/disp.c | 21 | ||||
-rw-r--r-- | monitor/main.c | 6 | ||||
-rw-r--r-- | monitor/mon.c | 14 | ||||
-rw-r--r-- | monitor/mon.h | 2 | ||||
-rw-r--r-- | plan_micro.pdf | bin | 79315 -> 80846 bytes | |||
-rw-r--r-- | plan_micro.tm | 8 | ||||
-rw-r--r-- | sched/Makefile | 2 | ||||
-rw-r--r-- | sched/_tags | 3 | ||||
-rw-r--r-- | sched/netlist_lexer.mll | 9 |
26 files changed, 626 insertions, 147 deletions
@@ -5,6 +5,8 @@ csim/csim sched/sched monitor/mon +asm/asm +cpu/os.rom *.o *.ps */*.net @@ -36,6 +36,12 @@ cpu/ The netlist for the CPU is generated by Caml code (and not MiniJazz code), therefore this directory also contains Caml files for generating netlists with Caml code (see `netlist_gen.mli` and `example_cpu.ml` for usage example). + +asm/ + An assembler used to compile assembly files for the CPU. Produces ROM files + readable by the simulator. + $ cd asm/ + $ make monitor/ A C program used to monitor the simulator. The monitor has many functionnalities : @@ -84,6 +90,10 @@ Compile the monitor : $ cd monitor/; make; cd .. +Compile the assembler : + + $ cd asm/; make; cd .. + Run the CPU with the monitor : $ cd cpu/; make @@ -244,22 +254,25 @@ default stdin, but can be redirected from a file using the -in option) and of writing the outputs at each step to a file (by default stdout, but can be redirected with -out). -The input format is extremely straightforward : at each step, read a line -containing for each input variable, *in the order given in the program file*, -either a binary value (represented by a series of bits given in the standard -order), either a decimal value prefixed with a slash (/), which is then -converted to binary according to the standard representation defined above. - -The output format contains at each step one line for each output variable, in -the format : -<variable name>\t<binary representation>\t<decimal representation> -The output contains an empty line at the end of every cycle. - When the simulator is launched, it sends an output describing the I/O mechanism of the simulated circuit : <number of inputs> <number of outputs>\n [for each input : <input size> <input name>\n] +The input format is extremely straightforward : at each step, read a line +begenning with the keyword FEED followed by, for each input variable, *in the +order given in the program file*, either a binary value (represented by a series +of bits given in the standard order), either a decimal value prefixed with a +slash (/), which is then converted to binary according to the standard +representation defined above. + +The output format contains at each step one line with the keyword FED, followed +by one line for each output variable, in the format : + + <variable name>\t<binary representation>\t<decimal representation> + +The output contains an empty line at the end of every cycle. + How ROMs are handled -------------------- @@ -301,7 +314,6 @@ NEXT STEPS ---------- - Finish ALU -- Code assembler - Code basic OS for the CPU diff --git a/asm/Makefile b/asm/Makefile new file mode 100644 index 0000000..8ac2004 --- /dev/null +++ b/asm/Makefile @@ -0,0 +1,10 @@ + +all: asm + +asm: assembler.ml asm.ml asmlex.mll asmpars.mly + ocamlbuild assembler.native + mv assembler.native asm + +clean: + rm asm + rm -r _build @@ -1,2 +1,4 @@ true: use_menhir +<*.ml>: debug +<*.byte>: use_unix, debug @@ -1,3 +1,5 @@ +exception Asm_error of string + type reg = int type imm = diff --git a/asm/asmlex.mll b/asm/asmlex.mll index fc77c93..b2c7718 100644 --- a/asm/asmlex.mll +++ b/asm/asmlex.mll @@ -54,8 +54,8 @@ let valh d = let c = Char.code d in if c >= Char.code '0' && c <= Char.code '9' then c - (Char.code '0') - else if c >= Char.code 'a' && c <= Char.code 'f' then c - (Char.code 'a') - else c - (Char.code 'A') + else if c >= Char.code 'a' && c <= Char.code 'f' then c - (Char.code 'a') + 10 + else c - (Char.code 'A') + 10 let read_16 n = let res = ref 0 in @@ -94,9 +94,13 @@ rule token = parse with Not_found -> ID id } | "0x" (((hexdigit)+) as n) { INT (read_16 n) } + | "'\\n'" { INT (Char.code '\n') } + | "'\\t'" { INT (Char.code '\t') } + | "'\\r'" { INT (Char.code '\r') } + | "'" (_ as c) "'" { INT (Char.code c) } | (digit)+ as n { INT (int_of_string n) } | "0b" (['0' '1']+ as n) { INT (read_2 n) } - | ['A'-'Z']+ as name { REG (List.assoc name regs) } + | ['A'-'Z']+ as name { try REG (List.assoc name regs) with Not_found -> raise (Asm_error ("no reg " ^ name))} | '$' (['0'-'7'] as n) { REG (Char.code n - (Char.code '0')) } | ".text" { TEXT } | ".data" { DATA } @@ -127,3 +131,4 @@ and comment = parse | eof { EOF } | '\n' { Lexing.new_line lexbuf; token lexbuf } | _ { comment lexbuf } + diff --git a/asm/asmpars.mly b/asm/asmpars.mly index e568127..c48c9ce 100644 --- a/asm/asmpars.mly +++ b/asm/asmpars.mly @@ -53,7 +53,7 @@ %% program: - TEXT NLB* is=instr* data? EOF + NLB* TEXT NLB* is=instr* data? EOF { { text = List.flatten is; lbls = !lbls2 } } @@ -66,10 +66,10 @@ datas: | WORD n=INT NLB+ { add ram (2*n) } labeli: - id=ID COLON { lbls2 := Imap.add id (!pc,true) !lbls2 } + id=ID COLON { lbls2 := Imap.add id (!pc,true) !lbls2 } labeld: - id=ID COLON { lbls2 := Imap.add id (!ram,false) !lbls2 } + id=ID COLON { lbls2 := Imap.add id (!ram,false) !lbls2 } instr: | labeli NLB* i=instr { i } @@ -129,9 +129,9 @@ _instr: | MOVE r1=REG r2=REG { add pc 2; [R (Add,r1,r2,0)] } | NOT r1=REG r2=REG { add pc 2; [R (Nor,r1,r2,0)] } | JZ r=REG l=ID { let l = li false 5 (Lab l) in - add pc 2; l @ [R (Jer,r,5,0)] } + add pc 2; l @ [R (Jer,5,r,0)] } | JNZ r=REG l=ID { let l = li false 5 (Lab l) in - add pc 2; l @ [R (Jner,r,5,0)] } + add pc 2; l @ [R (Jner,5,r,0)] } | POP r=REG { add pc 4; [Lw (r,7,0); Incri (7,2)] } | PUSH r=REG { add pc 4; [Incri (7,-2); Sw (r,7,0)] } | BYTE bs=int+ { List.map (fun b -> add pc 1; Byte b) bs } @@ -140,9 +140,9 @@ _instr: | ASCII s=STR { List.map (fun c -> add pc 1; Byte (Char.code c)) s } imm: - | id=ID { Lab id } - | n=int { Imm n } + | id=ID { Lab id } + | n=int { Imm n } int: - | n=INT { n } - | MINUS n=INT { - n } + | n=INT { n } + | MINUS n=INT { - n } diff --git a/asm/assembler.ml b/asm/assembler.ml index c794c98..35395e0 100644 --- a/asm/assembler.ml +++ b/asm/assembler.ml @@ -2,6 +2,8 @@ open Asm open Printf open Lexing +exception No_such_label of string + let init_string n f = let res = String.make n 'a' in for i = 0 to n - 1 do res.[i] <- f i done; res @@ -83,13 +85,13 @@ let print_program p = let pc = ref 0 in let value = function | Imm i -> i - | Lab l -> fst (Imap.find l p.lbls) in + | Lab l -> try fst (Imap.find l p.lbls) with Not_found -> raise (No_such_label l) in let value2 = function | Imm i -> i - | Lab l -> fst (Imap.find l p.lbls) - !pc in + | Lab l -> try fst (Imap.find l p.lbls) - !pc with Not_found -> raise (No_such_label l) in let value3 = function | Imm i -> i - | Lab l -> (byte 16 (fst (Imap.find l p.lbls))) lsr 8 in + | Lab l -> try (byte 16 (fst (Imap.find l p.lbls))) lsr 8 with Not_found -> raise (No_such_label l) in let get_reps = function | R (o,r1,r2,r3) -> r (code o) r1 r2 r3, sprintf "%s %s %s %s" (List.assoc o rev_keywords) (rts r1) (rts r2) (rts r3) diff --git a/cpu/Makefile b/cpu/Makefile index 898b007..7e92314 100644 --- a/cpu/Makefile +++ b/cpu/Makefile @@ -6,9 +6,13 @@ AUXILLARY=alu.ml SCHED=../sched/sched SIM=../csim/csim MON=../monitor/mon +ASM=../asm/asm -all: _build/cpu_opt.dumb - $(MON) $(SIM) -rom ROM0 prog_rom0.rom $< +all: _build/cpu_opt.dumb os.rom + $(MON) $(SIM) -rom ROM0 os.rom $< + +os.rom: os.asm + $(ASM) $< > $@ %.sim: _build/%.dumb $(SIM) -n 12 $< diff --git a/cpu/prog_rom0.rom b/cpu/ROM_count_seconds.rom index 7330dac..7330dac 100644 --- a/cpu/prog_rom0.rom +++ b/cpu/ROM_count_seconds.rom @@ -53,20 +53,114 @@ let nadder n a b = let a, b = nadder_with_carry n a b (const "0") in b ^. a +let neg n a = nadder n (not a) (one n) + let rec nsubber n a b = - zeroes n (* TODO *) + let r, c = nadder_with_carry n a (not b) (const "1") in + c ^. r + + + + +(* Some operations on Redundant Binary Representation + Each binary digit is encoded on 2 bits + + A n-digits number in RBR is written + [a_0, a'_0, a_1, a'_1, ..., a_(n-1), a'_(n-1)] + +*) + +(* [a] and [b] are encoded on 2n bits + [c_in] and [c_out] on 2 bits *) + +let rec rbr_nadder_with_carry n a b c_in = + + if n = 0 then (zeroes 0), c_in else + + let fa1s, fa1r = fulladder (a ** 1) (b ** 0) (b ** 1) in + let fa2s, fa2r = fulladder (c_in ** 1) (a ** 0) fa1s in + + let rec_s, rec_c = + rbr_nadder_with_carry (n - 1) + (a % (2, 2*n - 1)) + (b % (2, 2*n - 1)) + (fa1r ++ fa2r) + + in (c_in ** 0) ++ fa2s ++ rec_s, rec_c + + +let rbr_nadder n a b = + let s, c = rbr_nadder_with_carry n a b (zeroes 2) in + c ^. s + + +let bin_of_rbr n a c = + + (* Split even and odd bits *) + let rec split_bits n a = + if n = 0 then (zeroes 0, zeroes 0) + else + let even, odd = split_bits (n-1) (a % (2, 2*n - 1)) in + (a ** 0) ++ even, (a ** 1) ++ odd + + in + let a_even, a_odd = split_bits n a in + + nadder n a_even a_odd + + + +(* TODO : move to utils module *) +let rec range a b = if a > b then [] else a :: (range (a+1) b) + +(* Sépare en deux listes de même taille une liste de taille paire *) +let rec split_list = function + | [] -> [], [] + | [_] -> assert false + | x::y::tl -> let a, b = split_list tl in x::a, y::b + +let nmulu n a b start_signal = + let next_busy, set_next_busy = loop 1 in + let busy = start_signal ^| (reg 1 next_busy) in + + (* 'mule' est intialisé à b au début de la multiplication, + puis à chaque cycle est shifté de 1 bit vers la droite (donc perd le bit de poid faible) *) + let mule, set_mule = loop n in + let mule = set_mule (mux start_signal (((reg n mule) % (1, n-1)) ++ const "0") b) in + (* 'adde' est initialisé à a étendu sur 32 bits au début de la multiplication, + puis à chaque cycle est shifté de 1 bit vers la gauche (donc multiplié par 2) *) + let adde, set_adde = loop (2*n) in + let adde = set_adde (mux start_signal (const "0" ++ ((reg (2*n) adde) % (0, 2*n-2))) (a ++ (zeroes n))) in + + (* 'res' est un accumulateur qui contient le résultat que l'on calcule, + il est initialisé à 0 au début de la multiplication, et à chaque cycle + si mule[0] est non nul, on lui rajoute adde (c'est correct) *) + let res, set_res = loop (2*n) in + let t_res = mux start_signal (reg (2*n) res) (zeroes (2*n)) in + let res = set_res (mux (mule ** 0) t_res (nadder (2*n) adde t_res)) in + let work_remains = nonnull (n - 1) (mule % (1, n-1)) in + + let finished = + set_next_busy (busy ^& work_remains) ^. + (not work_remains) ^& busy in + + res % (0, n-1), res % (n, 2*n-1), finished + + + +let rec ndivu n a b start_signal = + zeroes (n-3) ++ const "110", zeroes (n-3) ++ const "110", start_signal + (* TODO : unsigned division, returns quotient and remainder *) -let rec nmul n a b = - zeroes n, zeroes n (* TODO : retuns lo and hi part of 32-bit answer *) +let rec nmul n a b start_signal = + zeroes (n-3) ++ const "101", zeroes (n-3) ++ const "101", start_signal + (* TODO : signed multiplication ; returns low part and high part *) -let rec ndiv n a b = - zeroes n, zeroes n (* TODO : returns quotient and remainder *) -let rec nmulu n a b = - zeroes n, zeroes n (* TODO : same as nmul but unsigned *) +let rec ndiv n a b start_signal = + zeroes (n - 3) ++ const "011", zeroes (n - 3) ++ const "011", start_signal + (* TODO : signed division *) -let rec ndivu n a b = - zeroes n, zeroes n (* TODO : save as ndiv but unsigned *) (* Shifts *) @@ -123,26 +217,31 @@ let alu_comparer n f0 f a b = let lte = mux (f ** 1) lte_signed lte_unsigned in mux f0 eq_ne lte -let alu_arith f1 f a b = +let alu_arith f0 f a b start_signal = (* See table for ALU below *) let add = nadder 16 a b in let sub = nsubber 16 a b in - let mul, mul2 = nmul 16 a b in - let div, div2 = ndiv 16 a b in - let mulu, mulu2 = nmulu 16 a b in - let divu, divu2 = ndivu 16 a b in + let mul, mul2, mul_end_signal = nmul 16 a b start_signal in + let div, div2, div_end_signal = ndiv 16 a b start_signal in + let mulu, mulu2, mulu_end_signal = nmulu 16 a b start_signal in + let divu, divu2, divu_end_signal = ndivu 16 a b start_signal in let q00 = mux (f ** 0) add sub in let q01 = mux (f ** 0) mul div in let q03 = mux (f ** 0) mulu divu in let q10 = mux (f ** 1) q00 q01 in let q11 = mux (f ** 1) q00 q03 in - let q = mux f1 q10 q11 in + let q = mux f0 q10 q11 in let r01 = mux (f ** 0) mul2 div2 in let r03 = mux (f ** 0) mulu2 divu2 in let r10 = mux (f ** 1) (zeroes 16) r01 in let r11 = mux (f ** 1) (zeroes 16) r03 in - let r = mux f1 r10 r11 in - q, r + let r = mux f0 r10 r11 in + let s01 = mux (f ** 0) mul_end_signal div_end_signal in + let s03 = mux (f ** 0) mulu_end_signal divu_end_signal in + let s10 = mux (f ** 1) start_signal s01 in + let s11 = mux (f ** 1) start_signal s03 in + let end_signal = mux f0 s10 s11 in + q, r, end_signal let alu_logic f a b = (* See table for ALU below *) @@ -155,9 +254,9 @@ let alu_shifts f a b = let q1 = mux (f ** 0) (op_lsr 16 a b) (op_asr 16 a b) in mux (f ** 1) (op_lsl 16 a b) q1 -let alu f1 f0 f a b = +let alu f1 f0 f a b start_signal = (* - f0 f1 f action + f1 f0 f action -- -- - ------ 0 0 0 add 0 0 1 sub @@ -176,12 +275,13 @@ let alu f1 f0 f a b = 1 1 2 lsr 1 1 3 asr *) - let arith, arith_r = alu_arith f1 f a b in + let arith, arith_r, arith_end_signal = alu_arith f0 f a b start_signal in let logic = alu_logic f a b in let shifts = alu_shifts f a b in - let q0 = mux f1 logic shifts in - let s = mux f0 arith q0 in - let r = mux f0 arith_r (zeroes 16) in - s, r + let q0 = mux f0 logic shifts in + let s = mux f1 arith q0 in + let r = mux f1 arith_r (zeroes 16) in + let end_signal = mux f1 arith_end_signal start_signal in + s, r, end_signal @@ -6,6 +6,8 @@ let ser_in_busy, save_ser_in_busy = loop 1 let dbg_ra, save_dbg_ra = loop 16 let dbg_read_data, save_dbg_read_data = loop 8 +let dbg_wa, save_dbg_wa = loop 16 +let dbg_write_data, save_dbg_write_data = loop 8 let cpu_ram ra we wa d = (* Ram chip has word size = 8 bits and address size = 16 bits @@ -54,6 +56,7 @@ let cpu_ram ra we wa d = let iser = nonnull 8 ser_in in let ser = mux iser ser ser_in in let ser_busy = nonnull 8 ser in + let ser_busy = mux read_ser ser_busy (const "0") in let read_data = save_ser_in_busy ser_busy ^. save_next_ser (mux read_ser ser (zeroes 8)) ^. @@ -61,6 +64,8 @@ let cpu_ram ra we wa d = save_dbg_ra ra ^. save_dbg_read_data read_data ^. + save_dbg_wa wa ^. + save_dbg_write_data d ^. read_data @@ -149,18 +154,18 @@ let rl, rh, i, ex, exf, pc = (* instruction : add/sub/mul/div/unsigned/or/and/xor/nor/lsl/lsr/asr *) let instr_alu = eq_c 3 (i_i % (2, 4)) 0b000 in - let f0 = i_i ** 0 in let f1 = i_i ** 1 in + let f0 = i_i ** 0 in let double_instr_alu = instr_alu ^& (not f1) ^& (i_f ** 1) ^& (ne_n 3 i_r (const "101")) in - let instr_alu = exec ^& instr_alu in - let instr_alu_2 = reg 1 (exec ^& double_instr_alu) in - let alu_d1, alu_d2 = alu f1 f0 i_f v_ra v_rb in - let wr = mux instr_alu wr i_r in - let rwd = mux instr_alu rwd alu_d1 in - let wr = mux instr_alu_2 wr (const "101") in - let rwd = mux instr_alu_2 rwd alu_d2 in - let exec_finished = mux double_instr_alu exec_finished instr_alu_2 in + let alu_d1, alu_d2, instr_alu_finished = alu f1 f0 i_f v_ra v_rb (exec ^& instr_alu) in + let instr_alu_store_2 = reg 1 (instr_alu_finished ^& double_instr_alu) in + let wr = mux instr_alu_finished wr i_r in + let rwd = mux instr_alu_finished rwd alu_d1 in + let wr = mux instr_alu_store_2 wr (const "101") in + let rwd = mux instr_alu_store_2 rwd alu_d2 in + let exec_finished = mux instr_alu exec_finished + (mux double_instr_alu instr_alu_finished instr_alu_store_2) in (* instruction : se/sne/slt/slte/sleu/sleu *) @@ -183,6 +188,7 @@ let rl, rh, i, ex, exf, pc = let instr_j = exec ^& eq_c 5 i_i 0b01000 in let next_pc = mux instr_j next_pc (nadder 16 pc (sign_extend 11 16 i_jd)) in (* instruction : jal *) + let link_pc = next_pc in let instr_jal = exec ^& eq_c 5 i_i 0b01001 in let next_pc = mux instr_jal next_pc (nadder 16 pc (sign_extend 11 16 i_jd)) in let instr_jalxx = instr_jal in @@ -196,7 +202,7 @@ let rl, rh, i, ex, exf, pc = let next_pc = mux cond_jxxr next_pc v_r in (* prologue for jal/jalr *) let wr = mux instr_jalxx wr (const "011") in - let rwd = mux instr_jalxx rwd next_pc in + let rwd = mux instr_jalxx rwd link_pc in (* instruction : lra *) let instr_lra = exec ^& eq_c 5 i_i 0b01100 in @@ -272,6 +278,11 @@ let rl, rh, i, ex, exf, pc = ( (* lil *) i_id ++ (mux instr_lixz (v_r % (8, 15)) (zeroes 8))) ( (* liu *) (mux instr_lixz (v_r % (0, 7)) (zeroes 8)) ++ i_id)) in + (* instruction : lie *) + let instr_lie = eq_c 5 i_i 0b11100 in + let wr = mux instr_lie wr i_r in + let rwd= mux instr_lie rwd (sign_extend 8 16 i_id) in + save_cpu_regs wr rwd ^. save_ram_read (cpu_ram ra we wa d) ^. save_next_read exec_finished ^. @@ -287,11 +298,13 @@ let p = [ "read_ilow", 1, rl; "read_ihi", 1, rh; - "exec_instr", 1, ex; - "exec_finished", 1, exf; - "instruction", 16, i; + "ex_instr", 1, ex; + "ex_finish", 1, exf; + "i", 16, i; "ra", 16, dbg_ra; "read_data", 8, dbg_read_data; + "wa", 16, dbg_wa; + "write_data", 8, dbg_write_data; "pc", 16, pc; "r0_Z", 16, r0; "r1_A", 16, r1; @@ -305,5 +318,5 @@ let p = "ser_in_busy", 1, ser_in_busy; ] -let () = Netlist_gen.print stdout p +let () = Netlist_printer.print_program stdout p diff --git a/cpu/netlist_gen.ml b/cpu/netlist_gen.ml index 016c595..956de91 100644 --- a/cpu/netlist_gen.ml +++ b/cpu/netlist_gen.ml @@ -59,7 +59,12 @@ let ( ++ ) v1 v2 = let x1, p = v1 p in let x2, p = v2 p in let sz1, sz2 = get_size p x1, get_size p x2 in - (Avar i), add p i (Econcat (x1, x2)) (sz1 + sz2) + if sz1 = 0 then + (x2), p + else if sz2 = 0 then + (x1), p + else + (Avar i), add p i (Econcat (x1, x2)) (sz1 + sz2) let ( ^| ) v1 v2 = let i = id "" in @@ -198,66 +203,3 @@ let program entries outputs = p_outputs = List.rev outputs } -(* Netlist printer *) - -let init_string n f = - let s = String.make n 'a' in - for i = 0 to n - 1 do - s.[i] <- f i - done; - s - -(* value to string *) -let vts bits = - init_string (Array.length bits) (fun i -> - if bits.(i) then '1' else '0') - -(* argument to string *) -let ats = function - | Avar id -> id - | Aconst n -> vts n - -let s_op = function - | Or -> "OR" - | Xor -> "XOR" - | And -> "AND" - | Nand -> "NAND" - -let print oc p = - let print_eq oc (s,e) = - let s_e = - match e with - | Earg a -> ats a - | Ereg s -> "REG " ^ s - | Enot a -> "NOT " ^ (ats a) - | Ebinop (b,a1,a2) -> (s_op b) ^ " " ^ (ats a1) ^ " " ^ (ats a2) - | Emux (a1,a2,a3) -> - "MUX " ^ (ats a1) ^ " " ^ (ats a2) ^ " " ^ (ats a3) - | Erom (n1,n2,a3) -> - "ROM " ^ (string_of_int n1) ^ " " ^ (string_of_int n2) ^ - " " ^ (ats a3) - | Eram (n1,n2,a3,a4,a5,a6) -> - "RAM " ^ (string_of_int n1) ^ " " ^ (string_of_int n2) ^ - " " ^ (ats a3) ^ " " ^ (ats a4) ^ " " ^ (ats a5) ^ - " " ^ (ats a6) - | Econcat (a1,a2) -> "CONCAT " ^ (ats a1) ^ " " ^ (ats a2) - | Eslice (n1,n2,a3) -> "SLICE " ^ (string_of_int n1) ^ " " ^ - (string_of_int n2) ^ " " ^ (ats a3) - | Eselect (n,a) -> "SELECT " ^ (string_of_int n) ^ " " ^ (ats a) in - Printf.fprintf oc "%s = %s\n" s s_e in - Printf.fprintf oc "INPUT "; - if p.p_inputs <> [] then - (Printf.fprintf oc "%s" (List.hd p.p_inputs); List.iter - (Printf.fprintf oc ", %s") (List.tl p.p_inputs)); - Printf.fprintf oc "\nOUTPUT "; - if p.p_outputs <> [] then - (Printf.fprintf oc "%s" (List.hd p.p_outputs); List.iter - (Printf.fprintf oc ", %s") (List.tl p.p_outputs)); - Printf.fprintf oc "\nVAR "; - let stts s t = if t = 1 then s else s ^ " : " ^ (string_of_int t) in - Pervasives.ignore (Env.fold (fun s t b -> - if b then Printf.fprintf oc "%s" (stts s t) - else Printf.fprintf oc ", %s" (stts s t); - false) p.p_vars true); - Printf.fprintf oc "\nIN\n"; - List.iter (print_eq oc) p.p_eqs diff --git a/cpu/netlist_gen.mli b/cpu/netlist_gen.mli index 67d4774..24cd6f1 100644 --- a/cpu/netlist_gen.mli +++ b/cpu/netlist_gen.mli @@ -1,7 +1,5 @@ type t -val print : out_channel -> Netlist_ast.program -> unit - val get : Netlist_ast.ident -> t val loop : int -> (t * (t -> t)) diff --git a/cpu/netlist_printer.ml b/cpu/netlist_printer.ml new file mode 100644 index 0000000..2c80d70 --- /dev/null +++ b/cpu/netlist_printer.ml @@ -0,0 +1,82 @@ +open Netlist_ast +open Format + +let rec print_env print lp sep rp ff env = + let first = ref true in + fprintf ff "%s" lp; + Env.iter + (fun x ty -> + if !first then + (first := false; fprintf ff "%a" print (x, ty)) + else + fprintf ff "%s%a" sep print (x, ty)) env; + fprintf ff "%s" rp + +let rec print_list print lp sep rp ff = function + | [] -> () + | x :: l -> + fprintf ff "%s%a" lp print x; + List.iter (fprintf ff "%s %a" sep print) l; + fprintf ff "%s" rp + +let print_ty ff n = + fprintf ff " : %d" n + +let print_bool ff b = + if b then + fprintf ff "1" + else + fprintf ff "0" + +let print_value ff a = + Array.iter (print_bool ff) a + +let print_arg ff arg = match arg with + | Aconst v -> print_value ff v + | Avar id -> fprintf ff "%s" id + +let print_op ff op = match op with + | And -> fprintf ff "AND" + | Nand -> fprintf ff "NAND" + | Or -> fprintf ff "OR" + | Xor -> fprintf ff "XOR" + +let print_exp ff e = match e with + | Earg a -> print_arg ff a + | Ereg x -> fprintf ff "REG %s" x + | Enot x -> fprintf ff "NOT %a" print_arg x + | Ebinop(op, x, y) -> fprintf ff "%a %a %a" print_op op print_arg x print_arg y + | Emux (c, x, y) -> fprintf ff "MUX %a %a %a " print_arg c print_arg x print_arg y + | Erom (addr, word, ra) -> fprintf ff "ROM %d %d %a" addr word print_arg ra + | Eram (addr, word, ra, we, wa, data) -> + fprintf ff "RAM %d %d %a %a %a %a" addr word + print_arg ra print_arg we + print_arg wa print_arg data + | Eselect (idx, x) -> fprintf ff "SELECT %d %a" idx print_arg x + | Econcat (x, y) -> fprintf ff "CONCAT %a %a" print_arg x print_arg y + | Eslice (min, max, x) -> fprintf ff "SLICE %d %d %a" min max print_arg x + +let print_eq ff (x, e) = + fprintf ff "%s = %a@." x print_exp e + +let print_var ff (x, ty) = + fprintf ff "@[%s%a@]" x print_ty ty + +let print_vars ff env = + fprintf ff "@[<v 2>VAR@,%a@]@.IN@," + (print_env print_var "" ", " "") env + +let print_idents ff ids = + let print_ident ff s = fprintf ff "%s" s in + print_list print_ident """,""" ff ids + +let print_program oc p = + let ff = formatter_of_out_channel oc in + fprintf ff "INPUT %a@." print_idents p.p_inputs; + fprintf ff "OUTPUT %a@." print_idents p.p_outputs; + print_vars ff p.p_vars; + List.iter (print_eq ff) p.p_eqs; + (* flush *) + fprintf ff "@." + + diff --git a/cpu/os.asm b/cpu/os.asm new file mode 100644 index 0000000..1617d6b --- /dev/null +++ b/cpu/os.asm @@ -0,0 +1,259 @@ +# CONVENTION: +# return value for functions : in register A +# arguments for functions : registers A, B, C, D +# all registers are caller-saved, except SP which is preserved by function calls + +.text + jal run_unit_tests + + li A msghello + jal ser_out_msg + + push Z +main_loop: + # Process serial input + jal check_input + jz A end_process_input + jal run_cmd +end_process_input: + + # Process clock ticking + pop D + li B _clock + lw B 0(B) + add D D B + push D + + jz B main_loop + li A msgtick + jal ser_out_msg + j main_loop + +# PROCEDURE: run_cmd +# ROLE: execute and clear command stored in cmdline +# ARGUMENTS: none +run_cmd: + push RA + + li A prompt + jal ser_out_msg + li A cmdline + jal ser_out_msg + li A endl + jal ser_out_msg + + li A error + jal ser_out_msg + + li A cmdline_used + sw Z 0(A) + + pop RA + jr RA + + +# PROCEDURE: ser_out_msg +# ROLE: write null-terminated string to serial output +# ARGUMENTS: address of string in register A +ser_out_msg: + li C _output +ser_out_msg_loop: + lb B 0(A) + jz B ser_out_msg_ret + sb B 0(C) + incri A 1 + j ser_out_msg_loop +ser_out_msg_ret: + jr RA + +# PROCEDURE: check_input +# ROLE: check if an input byte is available. if it is, and is different from '\n' (10), add it to cmdline +# ARGUMENTS: none +# RETURN VALUE: 1 if read byte was '\n', 0 otherwise +# WARNING: no buffer overflow check. +check_input: + li A _input + lb A 0(A) + jz A check_input_ret + move B A + sei A A '\n' + jz A add_b_to_string + move B Z +add_b_to_string: + push A + li A cmdline + li D cmdline_used + lw C 0(D) + add A A C + sb B 0(A) + incri C 1 + sw C 0(D) + pop A + jz A check_input +check_input_ret: + jr RA + +# PROCEDURE: run_unit_tests +# ROLE: check that CPU features work correctly ; displays message to serial output +# ARGUMENTS: none +run_unit_tests: + push RA + + li A testbegin + jal ser_out_msg + + move B Z + +unit_test_begin: + li D testlist + add D D B + lw D 0(D) + jz D unit_tests_done + + push B + push D + li A teststr + add A A B + lw A 0(A) + jal ser_out_msg + pop D + jalr D + li A testfail + jz B unit_test_failed + li A testok +unit_test_failed: + jal ser_out_msg + + pop B + addi B B 2 + j unit_test_begin + +unit_tests_done: + pop RA + jr RA + + +unit_test_0: # Addition / substraction + li B 1 + + li C 12 + li D 44 + add C C D + sei A C 56 + and B B A + + li C -7 + li D 7 + add C C D + se A C Z + and B B A + + li C 32767 + li D 32767 + add C C D + li D 2 + sub D Z D + se A C D + and B B A + + jr RA + +unit_test_1: # Unsigned multiplication + li B 1 + + li C 12 + li D 44 + mulu C C D + move D E + sei A C 528 + and B B A + se A D Z + and B B A + + li C 744 + li D 1244 + mulu C C D + move D E + sei A C 8032 + and B B A + sei A D 14 + and B B A + + jr RA + +unit_test_2: # Unsigned division + li B 1 + + li C 60 + li D 5 + divu C C D + move D E + sei A C 12 + and B B A + se A D Z + and B B A + + li C 14129 + li D 477 + divu C C D + move D E + sei A C 31 + and B B A + sei A D 272 + and B B A + + jr RA +unit_test_3: # Signed multiplication/division + li B 0 + jr RA + + + +# READ-ONLY PROGRAM DATA + +# General strings +msghello: + ascii "\nHello, world!\n" +msgtick: + ascii " ..." +prompt: + ascii "\n$ " +endl: + ascii "\n" +error: + ascii "Sorry but I'm to stupid to understand that.\n" + +# For unit-tests +testlist: + word unit_test_0 unit_test_1 unit_test_2 unit_test_3 0 +teststr: + word test0 test1 test2 test3 0 +testbegin: + ascii "Runing CPU unit tests...\n" +testok: + ascii "OK\n" +testfail: + ascii "FAIL\n" +test0: + ascii "Addition/substraction..........." +test1: + ascii "Unsigned multiplication........." +test2: + ascii "Unsigned division..............." +test3: + ascii "Signed multiplication/division.." + + + +.data +# Space where command-line is buffered from serial input +cmdline: + byte 256 +# Number of bytes used in the command-line buffer +cmdline_used: + word 1 + + + + + @@ -74,6 +74,13 @@ void read_inputs(t_machine *m, FILE *stream) { t_id var; t_program *p = m->prog; + int magic; + fscanf(stream, " %x", &magic); + if (magic != 0xFEED) { + fprintf(stderr, "(simulator) Protocol error.\n"); + exit(1); + } + if (p->n_inputs == 0) return; // nothing to do for (i = 0; i < p->n_inputs; i++) { @@ -213,6 +220,8 @@ void write_outputs(t_machine *m, FILE *stream) { t_value v, mask; t_program *p = m->prog; + fprintf(stream, "FED\n"); + for (i = 0; i < p->n_outputs; i++) { var = p->outputs[i]; fprintf(stream, "%s\t", p->vars[var].name); diff --git a/monitor/disp.c b/monitor/disp.c index 992c712..84dd941 100644 --- a/monitor/disp.c +++ b/monitor/disp.c @@ -86,19 +86,18 @@ void disp_display(t_mon *mon) { wprintw(wpstatus, "\nInputs:\n"); for (i = 0; i < mon->n_inputs; i++) { - wprintw(wpstatus, " %d. %s%s\t%s (%d)\t%s\n", + wprintw(wpstatus, "%s %d. %s (%d)\t%s\n", + (i == mon->ticker_input ? "T" : (i == mon->ser_in_in ? ">" : " ")), i, - (i == mon->ticker_input ? "T" : ""), - (i == mon->ser_in_in ? ">" : ""), mon->inputs[i].name, mon->inputs[i].size, mon->inputs[i].value); } if (mon->n_inputs == 0) wprintw(wpstatus, "\t(none)\n"); wprintw(wpstatus, "\nOutputs:\n"); for (i = 0; i < mon->n_outputs; i++) { - wprintw(wpstatus, " %d. %s%s\t%s\t%s\t%ld\n", i, - (i == mon->ser_out ? "<" : ""), - (i == mon->ser_in_busy_out ? "!" : ""), + wprintw(wpstatus, "%s %d. %s\t%s %ld\n", + (i == mon->ser_out ? "<" : (i == mon->ser_in_busy_out ? "!" : " ")), + i, mon->outputs[i].name, mon->outputs[i].v_bin, mon->outputs[i].v_int); } if (mon->n_outputs == 0) wprintw(wpstatus, "\t(none)\n"); @@ -147,4 +146,14 @@ void disp_display(t_mon *mon) { } +void disp_display_ser(t_mon *mon) { + if (mon->ser_out_buf != 0) { + wprintw(wpoutput, "%c", mon->ser_out_buf); + wrefresh(wpoutput); + mon->ser_out_buf = 0; + + wmove(wcmdline, 0, cmd_pos + 2); + wrefresh(wcmdline); + } +} diff --git a/monitor/main.c b/monitor/main.c index 1de722c..ff48dcf 100644 --- a/monitor/main.c +++ b/monitor/main.c @@ -36,6 +36,7 @@ int main(int argc, char *argv[]) { fprintf(stderr, "(simulator) Could not open mon2sim for reading (%s).\n", strerror(errno)); return 1; } + fprintf(stderr, "(simulator) Syncronization with monitor apparently OK.\n"); execv (argv[1], argv + 1); } @@ -55,6 +56,7 @@ int main(int argc, char *argv[]) { fprintf(stderr, "\nError while launching simulator (%d).\n", err); goto finish; } + fprintf(stderr, "(monitor) Syncronization with simulator apparently OK.\n"); // Setup display disp_init(); @@ -65,6 +67,10 @@ int main(int argc, char *argv[]) { // clean up disp_finish(); + if (mon.status == MS_PERROR) { + fprintf(stderr, "(monitor) Exiting due to protocol error.\n"); + } + finish: kill(sim_pid, SIGTERM); waitpid(sim_pid); diff --git a/monitor/mon.c b/monitor/mon.c index 19055c7..780e8ba 100644 --- a/monitor/mon.c +++ b/monitor/mon.c @@ -82,7 +82,7 @@ void mon_loop(t_mon *mon) { int displayer_steps = 0; - while (mon->status != MS_FINISH) { + while (1) { handle_kbd(mon); if (mon->status == MS_AUTO) { mon_step(mon); @@ -125,8 +125,10 @@ void mon_loop(t_mon *mon) { } int sleep = 1000000 / mon->target_freq - mon->calc_time_usec; if (sleep > 0) usleep(sleep); - } else { + } else if (mon->status == MS_RUN) { usleep(10000); + } else { + break; } } } @@ -266,12 +268,19 @@ void mon_step(t_mon *mon) { } // Send inputs to simulator + fprintf(mon->to_sim, "FEED\n"); for (i = 0; i < mon->n_inputs; i++) { fprintf(mon->to_sim, "%s\n", mon->inputs[i].value); } fflush(mon->to_sim); // Read outputs from simulator + int magic; + fscanf(mon->from_sim, " %x", &magic); + if (magic != 0xFED) { + mon->status = MS_PERROR; + return; + } for (i = 0; i < mon->n_outputs; i++) { fscanf(mon->from_sim, " %s %s %d", mon->outputs[i].name, @@ -285,4 +294,5 @@ void mon_step(t_mon *mon) { } mon->step++; + disp_display_ser(mon); } diff --git a/monitor/mon.h b/monitor/mon.h index 0040eda..4430e5f 100644 --- a/monitor/mon.h +++ b/monitor/mon.h @@ -20,6 +20,7 @@ typedef struct { } t_input; typedef enum { + MS_PERROR, MS_FINISH, MS_RUN, MS_AUTO, @@ -61,6 +62,7 @@ typedef struct { void disp_init(); void disp_display(t_mon *mon); +void disp_display_ser(t_mon *mon); void disp_finish(); void handle_kbd(t_mon *mon); diff --git a/plan_micro.pdf b/plan_micro.pdf Binary files differindex e67dc86..d1e0dcc 100644 --- a/plan_micro.pdf +++ b/plan_micro.pdf diff --git a/plan_micro.tm b/plan_micro.tm index 0c6020e..158ffb5 100644 --- a/plan_micro.tm +++ b/plan_micro.tm @@ -137,8 +137,10 @@ (16 bits)>|<cell|>>|<row|<cell|10110>|<cell|R>|<cell|*>|<cell|lbr>|<cell|<math|R<rsub|lo>\<leftarrow\>mem<around*|(|R<rsub|A>+R<rsub|B>|)> ; R<rsub|hi>\<leftarrow\>0> (8 bits)>|<cell|>>|<row|<cell|10111>|<cell|R>|<cell|*>|<cell|sbr>|<cell|<math|mem<around*|(|R<rsub|A>+R<rsub|B>|)>\<leftarrow\>R<rsub|lo><rsup|>> (8 bits)>|<cell|>>|<row|<cell|11000>|<cell|I>|<cell|>|<cell|lil>|<cell|<math|R<rsub|lo>\<leftarrow\>d>>|<cell|>>|<row|<cell|11001>|<cell|I>|<cell|>|<cell|lilz>|<cell|<math|R<rsub|lo>\<leftarrow\>d - ; R<rsub|hi>\<leftarrow\>0>>|<cell|>>|<row|<cell|11010>|<cell|I>|<cell|>|<cell|liu>|<cell|<math|R<rsub|hi>\<leftarrow\>d>>|<cell|>>|<row|<cell|11011>|<cell|I>|<cell|>|<cell|liuz>|<cell|<math|R<rsub|hi>\<leftarrow\>d - ; R<rsub|lo>\<leftarrow\>0>>|<cell|>>|<row|<cell|11100>|<cell|>|<cell|<em|>>|<cell|<em|nop>>|<cell|>|<cell|>>|<row|<cell|11101>|<cell|>|<cell|>|<cell|<em|nop>>|<cell|>|<cell|>>|<row|<cell|11110>|<cell|>|<cell|>|<cell|<em|nop>>|<cell|>|<cell|>>|<row|<cell|11111>|<cell|>|<cell|>|<cell|nop<samp|>>|<cell|<math|\<varnothing\>>>|<cell|>>>>>|Instructions + ; R<rsub|hi>\<leftarrow\>0>>|<cell|(<math|d> non + signé)>>|<row|<cell|11010>|<cell|I>|<cell|>|<cell|liu>|<cell|<math|R<rsub|hi>\<leftarrow\>d>>|<cell|>>|<row|<cell|11011>|<cell|I>|<cell|>|<cell|liuz>|<cell|<math|R<rsub|hi>\<leftarrow\>d + ; R<rsub|lo>\<leftarrow\>0>>|<cell|>>|<row|<cell|11100>|<cell|I>|<cell|<em|>>|<cell|lie>|<cell|<math|R\<leftarrow\>sign_extend<rsub|8><rsup|16><around*|(|d|)>>>|<cell|(<math|d> + signé)>>|<row|<cell|11101>|<cell|>|<cell|>|<cell|<em|nop>>|<cell|>|<cell|>>|<row|<cell|11110>|<cell|>|<cell|>|<cell|<em|nop>>|<cell|>|<cell|>>|<row|<cell|11111>|<cell|>|<cell|>|<cell|nop<samp|>>|<cell|<math|\<varnothing\>>>|<cell|>>>>>|Instructions reconnues par le microproceseur> L'assembleur propose également quelques instructions \S étendues \T @@ -181,7 +183,7 @@ <associate|auto-11|<tuple|5|2>> <associate|auto-12|<tuple|4|2>> <associate|auto-13|<tuple|3|3>> - <associate|auto-14|<tuple|4|5>> + <associate|auto-14|<tuple|4|4>> <associate|auto-15|<tuple|5|?>> <associate|auto-16|<tuple|4|?>> <associate|auto-17|<tuple|5|?>> diff --git a/sched/Makefile b/sched/Makefile index 4d36b96..35d6ddc 100644 --- a/sched/Makefile +++ b/sched/Makefile @@ -3,7 +3,7 @@ IN=graph.ml main.ml netlist_ast.ml netlist_dumb.ml netlist_lexer.mll netlist.ml all: sched sched: $(IN) - ocamlbuild -libs unix main.native + ocamlbuild main.native mv main.native sched clean: diff --git a/sched/_tags b/sched/_tags index 503ce62..007e22c 100644 --- a/sched/_tags +++ b/sched/_tags @@ -1,3 +1,4 @@ true: use_menhir <*.ml>: debug -<*.byte>: use_unix, debug
\ No newline at end of file +<*.byte>: use_unix, debug +<*.native>: use_unix diff --git a/sched/netlist_lexer.mll b/sched/netlist_lexer.mll index 60cb223..ec27367 100644 --- a/sched/netlist_lexer.mll +++ b/sched/netlist_lexer.mll @@ -1,5 +1,6 @@ { open Netlist_parser +open Lexing exception Eof let keyword_list = @@ -22,10 +23,16 @@ let keyword_list = "XOR", XOR; ] +let newline lexbuf = + let pos = lexbuf.lex_curr_p in + lexbuf.lex_curr_p <- + { pos with pos_lnum = pos.pos_lnum + 1; pos_bol = pos.pos_cnum } + } rule token = parse - [' ' '\t' '\n'] { token lexbuf } (* skip blanks *) + | '\n' { newline lexbuf ; token lexbuf } + | [' ' '\t'] { token lexbuf } (* skip blanks *) | "=" { EQUAL } | ":" { COLON } | "," { COMMA } |