22
33import re
44from pathlib import Path
5- from typing import Annotated , Any , TypedDict , Unpack , cast
5+ from typing import Annotated , Any , TypedDict , Unpack , cast , overload
66
77import yaml
88from jinja2 import Environment , FileSystemLoader , StrictUndefined
@@ -78,20 +78,44 @@ def configs(yaml_path: Path):
7878@app .command ()
7979def build (
8080 yaml_path : Path ,
81+ cpu_config_name : Annotated [str | None , Option ("-c" , "--config" )] = None ,
8182 width : Annotated [int , Option ("-w" , "--width" )] = 16 ,
8283 height : Annotated [int , Option ("-h" , "--height" )] = 16 ,
8384 size : Annotated [int | None , Option ("-s" , "--size" )] = None ,
8485 output : Annotated [Path | None , Option ("-o" , "--output" )] = None ,
85- cpu_only : bool = False ,
86+ include_all : Annotated [bool , Option ("--all" )] = False ,
87+ include_cpu : Annotated [bool , Option ("--cpu" )] = False ,
88+ include_peripherals : Annotated [bool , Option ("--peripherals" )] = False ,
8689):
8790 """Generate a CPU schematic."""
8891
8992 if size :
9093 width = size
9194 height = size
9295
96+ if include_all or not (include_cpu or include_peripherals ):
97+ include_cpu = True
98+ include_peripherals = True
99+
93100 config = BuildConfig .load (yaml_path )
94101
102+ if cpu_config_name :
103+ with config .configs .open ("rb" ) as f :
104+ cpu_configs : ConfigsYaml = yaml .load (f , yaml .Loader )
105+
106+ if cpu_config_name not in cpu_configs ["configs" ]:
107+ raise KeyError (f"Unknown config name: { cpu_config_name } " )
108+
109+ configs (config .configs )
110+
111+ config_code = (
112+ (config .configs .parent / cpu_config_name )
113+ .with_suffix (".mlog" )
114+ .read_text ("utf-8" )
115+ )
116+ else :
117+ config_code = ""
118+
95119 worker_output = get_template_output_path (config .templates .worker )
96120 worker_code = render_template (
97121 config .templates .worker ,
@@ -125,59 +149,103 @@ def build(
125149
126150 schem = Schematic ()
127151
152+ @overload
153+ def add_peripheral (block : Block ) -> None : ...
154+
155+ @overload
156+ def add_peripheral (block : Schematic , x : int , y : int ) -> None : ...
157+
158+ def add_peripheral (block : Block | Schematic , x : int = 0 , y : int = 0 ):
159+ if not include_peripherals :
160+ return
161+ match block :
162+ case Block ():
163+ schem .add_block (block )
164+ case Schematic ():
165+ schem .add_schem (block , x , y )
166+
167+ def add_cpu (block : Block ):
168+ if include_cpu :
169+ schem .add_block (block )
170+
171+ def add_label (x : int , y : int , ** labels : Unpack [Labels ]):
172+ label = "\n " .join (
173+ template .format (label )
174+ for key , template in [
175+ ("up" , "{} ⇧" ),
176+ ("left" , "⇦ {}" ),
177+ ("right" , "{} ⇨" ),
178+ ("down" , "{} ⇩" ),
179+ ]
180+ if (label := labels .get (key ))
181+ )
182+ add_peripheral (
183+ Block (
184+ block = Content .MESSAGE ,
185+ x = x ,
186+ y = y ,
187+ config = label ,
188+ rotation = 0 ,
189+ )
190+ )
191+
192+ def add_with_label (block : Block , ** labels : Unpack [Labels ]):
193+ add_label (block .x - 1 , block .y , ** labels )
194+ add_peripheral (block )
195+
196+ # peripherals
197+
128198 for x in lenrange (0 , 16 ):
129199 for y in lenrange (0 , 16 ):
130- schem . add_block (simple_block (BEContent .TILE_LOGIC_DISPLAY , x , y ))
200+ add_peripheral (simple_block (BEContent .TILE_LOGIC_DISPLAY , x , y ))
131201
132202 display_link = ProcessorLink (0 , 0 , "" )
133203
134- schem . add_schem (lookups_schem , 0 , 16 )
204+ add_peripheral (lookups_schem , 0 , 16 )
135205 lookup_links = [ProcessorLink (x = i % 4 , y = 16 + i // 4 , name = "" ) for i in range (16 )]
136206
137- add_label (schem , 4 , 19 , right = "UART0, UART2" , down = "LABELS" )
138- schem . add_block (simple_block (Content .WORLD_CELL , 4 , 18 ))
139- schem . add_block (simple_block (Content .WORLD_CELL , 4 , 17 ))
140- add_label (schem , 4 , 16 , up = "COSTS" , right = "UART1, UART3" )
207+ add_label (4 , 19 , right = "UART0, UART2" , down = "LABELS" )
208+ add_peripheral (simple_block (Content .WORLD_CELL , 4 , 18 ))
209+ add_peripheral (simple_block (Content .WORLD_CELL , 4 , 17 ))
210+ add_label (4 , 16 , up = "COSTS" , right = "UART1, UART3" )
141211
142212 labels_link = ProcessorLink (4 , 18 , "" )
143213 costs_link = ProcessorLink (4 , 17 , "" )
144214
145215 uart_links = list [ProcessorLink ]()
146216 for x in lenrange (5 , 4 , 2 ):
147217 for y in lenrange (18 , - 4 , - 2 ):
148- schem . add_block (simple_block (Content .MEMORY_BANK , x , y ))
218+ add_peripheral (simple_block (Content .MEMORY_BANK , x , y ))
149219 uart_links .append (ProcessorLink (x , y , "" ))
150220
151- schem .add_block (simple_block (Content .MEMORY_CELL , 9 , 19 ))
152- schem .add_schem (ram_schem , 9 , 18 )
153- schem .add_schem (ram_schem , 9 , 17 )
154- schem .add_block (Block (Content .MICRO_PROCESSOR , 9 , 16 , ProcessorConfig ("" , []), 0 ))
221+ add_peripheral (simple_block (Content .MEMORY_CELL , 9 , 19 ))
222+ add_peripheral (ram_schem , 9 , 18 )
223+ add_peripheral (ram_schem , 9 , 17 )
224+ add_peripheral (
225+ Block (Content .MICRO_PROCESSOR , 9 , 16 , ProcessorConfig (config_code , []), 0 )
226+ )
155227
156228 registers_link = ProcessorLink (9 , 19 , "" )
157229 csrs_link = ProcessorLink (9 , 18 , "" )
158230 incr_link = ProcessorLink (9 , 17 , "" )
159231 config_link = ProcessorLink (9 , 16 , "" )
160232
161233 add_with_label (
162- schem ,
163234 simple_block (Content .MESSAGE , 11 , 19 ),
164235 left = "REGISTERS" ,
165236 right = "ERROR_OUTPUT" ,
166237 )
167238 add_with_label (
168- schem ,
169239 Block (Content .SWITCH , 11 , 18 , False , 0 ),
170240 left = "CSRS" ,
171241 right = "POWER_SWITCH" ,
172242 )
173243 add_with_label (
174- schem ,
175244 Block (Content .SWITCH , 11 , 17 , False , 0 ),
176245 left = "INCR" ,
177246 right = "PAUSE_SWITCH" ,
178247 )
179248 add_with_label (
180- schem ,
181249 Block (Content .SWITCH , 11 , 16 , False , 0 ),
182250 left = "CONFIG" ,
183251 right = "SINGLE_STEP_SWITCH" ,
@@ -188,11 +256,9 @@ def build(
188256 pause_switch_link = ProcessorLink (11 , 17 , "" )
189257 single_step_switch_link = ProcessorLink (11 , 16 , "" )
190258
191- # hack
192- if cpu_only :
193- schem = Schematic ()
259+ # CPU
194260
195- schem . add_block (
261+ add_cpu (
196262 Block (
197263 block = Content .WORLD_PROCESSOR ,
198264 x = 16 ,
@@ -229,7 +295,7 @@ def build(
229295 if x == 16 and y == 0 :
230296 continue
231297
232- schem . add_block (
298+ add_cpu (
233299 Block (
234300 block = Content .WORLD_PROCESSOR ,
235301 x = x ,
@@ -282,33 +348,6 @@ class Labels(TypedDict, total=False):
282348 down : str
283349
284350
285- def add_label (schem : Schematic , x : int , y : int , ** labels : Unpack [Labels ]):
286- label = "\n " .join (
287- template .format (label )
288- for key , template in [
289- ("up" , "{} ⇧" ),
290- ("left" , "⇦ {}" ),
291- ("right" , "{} ⇨" ),
292- ("down" , "{} ⇩" ),
293- ]
294- if (label := labels .get (key ))
295- )
296- schem .add_block (
297- Block (
298- block = Content .MESSAGE ,
299- x = x ,
300- y = y ,
301- config = label ,
302- rotation = 0 ,
303- )
304- )
305-
306-
307- def add_with_label (schem : Schematic , block : Block , ** labels : Unpack [Labels ]):
308- add_label (schem , block .x - 1 , block .y , ** labels )
309- schem .add_block (block )
310-
311-
312351def create_jinja_env (template_dir : Path ):
313352 env = Environment (
314353 loader = FileSystemLoader (template_dir ),
0 commit comments