summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--README36
-rw-r--r--asm/Makefile10
-rw-r--r--asm/_tags2
-rw-r--r--asm/asm.ml2
-rw-r--r--asm/asmlex.mll11
-rw-r--r--asm/asmpars.mly18
-rw-r--r--asm/assembler.ml8
-rw-r--r--cpu/Makefile8
-rw-r--r--cpu/ROM_count_seconds.rom (renamed from cpu/prog_rom0.rom)0
-rw-r--r--cpu/alu.ml148
-rw-r--r--cpu/cpu.ml41
-rw-r--r--cpu/netlist_gen.ml70
-rw-r--r--cpu/netlist_gen.mli2
-rw-r--r--cpu/netlist_printer.ml82
-rw-r--r--cpu/os.asm259
-rw-r--r--csim/sim.c9
-rw-r--r--monitor/disp.c21
-rw-r--r--monitor/main.c6
-rw-r--r--monitor/mon.c14
-rw-r--r--monitor/mon.h2
-rw-r--r--plan_micro.pdfbin79315 -> 80846 bytes
-rw-r--r--plan_micro.tm8
-rw-r--r--sched/Makefile2
-rw-r--r--sched/_tags3
-rw-r--r--sched/netlist_lexer.mll9
26 files changed, 626 insertions, 147 deletions
diff --git a/.gitignore b/.gitignore
index eda51f2..49eedec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,8 @@
csim/csim
sched/sched
monitor/mon
+asm/asm
+cpu/os.rom
*.o
*.ps
*/*.net
diff --git a/README b/README
index 1d1be18..d3ab4c2 100644
--- a/README
+++ b/README
@@ -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
diff --git a/asm/_tags b/asm/_tags
index b2f3704..3ed8b5a 100644
--- a/asm/_tags
+++ b/asm/_tags
@@ -1,2 +1,4 @@
true: use_menhir
+<*.ml>: debug
+<*.byte>: use_unix, debug
diff --git a/asm/asm.ml b/asm/asm.ml
index b52eda4..21e83d4 100644
--- a/asm/asm.ml
+++ b/asm/asm.ml
@@ -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
diff --git a/cpu/alu.ml b/cpu/alu.ml
index f437bd3..ff98c23 100644
--- a/cpu/alu.ml
+++ b/cpu/alu.ml
@@ -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
diff --git a/cpu/cpu.ml b/cpu/cpu.ml
index b7e394b..78caa30 100644
--- a/cpu/cpu.ml
+++ b/cpu/cpu.ml
@@ -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
+
+
+
+
+
diff --git a/csim/sim.c b/csim/sim.c
index 1dd2791..4451d0e 100644
--- a/csim/sim.c
+++ b/csim/sim.c
@@ -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
index e67dc86..d1e0dcc 100644
--- a/plan_micro.pdf
+++ b/plan_micro.pdf
Binary files differ
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 }