Added README-gv319 updates.

This commit is contained in:
Giorgos Vyronos 2022-03-02 18:31:53 +00:00
parent 05951c99b7
commit fba1222d27
2 changed files with 178 additions and 230 deletions

View file

@ -1,118 +1,25 @@
# Example README for individual code submission
## Instructions
* This file should be submitted (changed) on branch `hlp22-indiv-assess-<login>` of either your own repo or your group repo
* replace `<login>` in filename `README-<login>.md` by your login - in his example `<login> = tomcl`
* name the branch as above, including your login. This branch is used only for your submission.
* A link to the repo and branch must be on the `indiv` sheet of Tom Clarke's Team [google spreadsheet](https://docs.google.com/spreadsheets/d/1prQ5usnpu36FgtbsMO8j6_mwbdd34haSMOQKN2OkLBA/edit?usp=sharing)
* The repo you use **must have your marker added as collaborator** (github login is on indiv assessment spreadsheet page)
* Delete these instructions from your version of this readme
* Delete my comments from your version of the readme (it is an example, not something you add lines to).
Keep the headings and **replace the admin section links and notes with correct ones**.
* Link to the sourcefile your code is contained in (drawblock or symbol) with an absolute hyperlink
to your repo and branch
* Specify which code section and file you are doing as in my ppt (1,2,3), (buswire,symbol)
* Add any changes to my section code allocations. This must be consistent with what has been
recorded in your team's file in my Team contributions repo](https://github.com/tomcl/hlp22docs/blob/main/README.md)
main branch ./TeamN.md (N = 1 - 9) file. The team contrib repo is as official record. This file will be
used marking and should have line numbers for easy access. Expect to be marked down if your marker
cannot easily find everything via links from this README.
## Team Shared Team.md
[Team Contribution Repo](https://github.com/tomcl/hlp22docs/blob/main/README.md)
* A file in this repo file is common to the team contains who is responsible for which parts of code
* Fork and clone it
* Any team member can make agreed by team commits. First commit before Wed 23 Fen 16:00.
* Changes in who does what are recorded by altering list of functions AND
as extra lines in this file. See sample file in [README](https://github.com/tomcl/hlp22docs/blob/main/README.md)
## Admin and quick access links
*link to your teamN.md file*
[Common repo TeamN file](https://github.com/tomcl/hlp22docs/blob/main/README.md)
[Common repo Team 6 file](https://github.com/tomcl/hlp22docs/blob/main/Team6.md)
[Buswire (section 3)](src/renderer/drawblock/buswire.fs)
Link to altered files:
* [Symbol (Section 2)](src/Renderer/DrawBlock/Symbol.fs)
* [Sheet (Section 2)](src/Renderer/DrawBlock/Sheet.fs)
* [Renderer (Section 2)](src/Renderer/Renderer.fs)
Section 3 on my file is lines : 700-1100
I am also responsible for lines 100-120 (functions mySplurgeFunc, my2ndSplurgeFunc)
Anything else you need to say about what you are or are not responsible for.
## Code partitioning notes (don't copy this section in your submitted README - delete it)
Insert clear comments in the source files indicating where each person's code starts and stops
```
//---------------------------------------------------------------------------------//
//--------------------TJWC CODE SECTION STARTS-------------------------------------//
//---------------------------------------------------------------------------------//
```
### Separating code into 3 modules (in different files)
Groups can - **if they wish** - modularise their buswire or symbol files into 2 or 3 modules in separate files
1. Symbol1
2. Symbol2
3. Symbol3
With each module referencing the ones before with `open`.
A top-level module `Symbol` or `BusWire` after these three must contain functions exported anywhere outside symbol so that
references in the rest of the code still work.
```
Symbol.fs
let interface1 = Symbol1.interface1
let interface2 = Symbol1.Interface2
let interface3 = Symbol2.interface3
```
### Submodules within one file
Less dramatic, but still useful for modularity. Groups can - **if they wish** - modularise their buswire or symbol files into 3 submodules inside the existing file
```
Symbol.fs
module symbol1 =
let symbol1defn = ...
module symbol2
open symbol1
let symbol2defn
module symbol3 =
open symbol1
open symbol2
let symbol3 defn =
```
Again you will need to mend references - because open Symbol in some other part of Issie would need to become open Symbol.Symbol1, open Symbol.Symbol2 etc to pick up exported code in the submodules. you can add exports to Symbol.fs outside the three submodules as
when each moduel is in separate files.
## Note on assessment
The aim of assessment if that the first two sections should be fairly straightforward and demonstrate basic knowledge
of how to write FP code. They can achieve overall marks up to 70% without extension work. Those working on
significant extensions should put extra effort into these and not complex analysis section since the
analysis marks can accept well-written code supporting extensions as evidence of understanding.
The aim of this is so that you get marks for good code,
if you can write signiifcant good code without being motivated to write reports.
There are signiifcant differences between different code sections, and also things which
change dependning on what your base types are and how ambitious your code rewrite it. Ask early
if you are concerned about how this assessment will impact you. There will be ways to reward code
writing which can be found if need be in individual cases.
I am responsible for making the following changes in my code:
* __Symbol.fs:__ Lines : 718-1315 (Section 2) and Lines : 97-102 (stransform_fsm)
- Includes changes to existing code for Section 2 and new functions implementing the extensions.
* __Sheet.fs:__ Lines 86, 859-863 (Extensions)
- Includes changes required to make extensions for rotation work.
* __Renderer.fs:__ Lines 151 (Extensions)
- Includes changes required to make extensions for UI rotation work.
## Code Quality
This will be assessed based on the code. You can **but do not have to** highlight here things you are particularly proud of and want markers to look at (up to 3) as short bullet points:
Things to note:
* Naming of `myGoodName`, `myWonderfulLongName`
* New function boundaries: `topfun` -> `firstfun`, `topfun` -> `secondFun`
* New types: MyGoodType
@ -123,72 +30,109 @@ Your code will all be assessed anyway, so this is optional.
## Analysis
This combines analysis of **issues in existing code** with **proof or analysis of how/why the new code works**.
The marking combines both parts. If new code already works and is well written (especially if it is
demonstrated to have significant value in terms of ability to support extensions (see Extensions below)
less evidence will be needed for a high mark in this section.
The analysis here demonstrates that you understand the problems in the old code.
If the old code has no or few problems you can say this.
### Types
_The types decided in the first part of Symbol.fs were `STransform` of type `Rotation` and `PortOrientationOffset` of type {`PortOrientation`,`Offset`} each with its four possible cases to be used to describe
the different rotations fo the symbol and the side of the symbol its ports are at each rotation._
_`APortOffsetsMap` of type `Map<string,PortOrientationOffset>` was used to describe the port locations relative to the top left corner of the symbol.
This map uses string keys `I0..IN` and `O0..ON` to correctly distinguish and store the input and output port offsets in the map._
Anything you say here may if necessary be tested in the 5 min feedback interview to check understanding.
### Changes to pre-existing code
### Issues in Existing Code
#### Bad Function list
Overall small changes were made to the pre-existing code, as the main focus was the correct implementation
of the extensions and symbol enhancements and to ensure their full functionality.
List any problems with the existing code **concisely** as numbered points one function per point. State why
the problem exists. List only functions with **significant problems**. You can should refer to XML comments
in your refactored code where this helps. You may note the worst 3 functions even if they have problems that are not
significant.
Minor changes were made by removing unnecessary parentheses adding comments where necessary and refactoring the code where unnecessary arguments were passed to functions.
* if function is poorly documented say why this is necessary (what is not obvious from a good name +
* parameter names + types).
* if function has bad name say why this is confusing
* if a function is poorly written indicate what rewriting would improve this (briefly). You can
refer to your code if this helps.
#### Other problems
#### changeLsbf, changeConstantf
Renamed to changeLSBbits and changeConstant respectively to avoid confusion of f being regarded as using an input of type float.
State **concisely** Issues with existing code, or in refactoring for new types, that do not fit into per function list.
Again numbered points, at most 3. Choose the most inmportant if you have too much to say. You can should
refer to documentation (not XML docs) in code where this helps.
#### createCustomPortNamesMap
Removed parantheses and unnecessary use of input parameter n, as it wasn't used and so that it wasn't required when used.
#### getInputPortsPositionMap, getOutputPortsPositionMap,getPortLocations, getInputPortLocation, getOutputPortLocation
Since getInputPortsPositionMap, getOutputPortsPositionMap are now using getGlobalPortPos which is explained later on in the Extensions section the input parameter of model is not required but only the Symbol list.
Therefore, to avoid confusion and improve readability it was removed as a parameter and as input to the following function addressed above.
Apart from these changes the main focus was targeted at the Extensions of this Section due to their importance.
### Analysis of how/why code works
The code described below are the fully working implemented Symbol - enhancements for the Individual Coding of Section 2 ([Project Spec: Slide 6](https://intranet.ee.ic.ac.uk/t.clarke/hlp/lectures/project22-spec.pdf))
This section need not contain analysis if the code can be demonstarted working. In
that case list as bullet points the features you will demonstarte (quickly) in the 5 min
interview.
* If code works fully and can be demonstrated in the 5 minute feedback interview no analysis is needed.
* If code will be manually tested in interview say what the tests are that supplement your analysis
* Interview code must be the assessed branch (not something else, or using later group code)
* A good way to show code works is to explain how it differs from existing working code and how existing
functionality is preserved.
The code demonstrated in the 5 minute feedback will be to:
* Show different UI implementations to perform rotation for each symbol.
* Show how ports on different symbols are mapped with rotation to the different sides of the symbol.
* Show how the wiring between symbols is also altered with each rotation.
* Show that the bounding box of each symbol changes with each rotation for each symbol.
# Extensions
## 1. Locate port position and orientation, given symbol position and orientation
### Changes in files:
- __Symbol.fs__
- `743-748`canvasPortLocation
- `753-761` getGlobalPortPos
Extensions are required for mark > 70 and optional for mark below 70. High marks on
the first two sections cannot boost extensions mark if this is lower than them.
### Explanation:
Functions `canvasPortLocation` and `getGlobalPortPos` were created to produce the "Global" Coordinates of the ports
for each symbol at any given rotation and position. `canvasPortLocation` extracts the `APortOffsetsMap` of the specified
symbol and returns a list of the global XYPos ports of the symbol by combining the offsets with the top-left corner of the symbol.
These coordinates are shown by toggling Developer tools in Issie and are outputted every time a selected symbol is rotated
showing its global coordinates in the order described in Types. Keep in mind the coordinates shown are those before the symbol is rotated.
Similar to `canvasPortLocation`, `getGlobalPortPos` is used to generate the "Global" XYPos of a specified Port on the Canvas
given the port and symbol specified. Since, the `APortOffset` map and `STransform` are part of the Symbol type, the entire symbol is passed to the function,
rather than these separately. After categorizing the port passed to the function as type input or output, the appropriate index of the port is extracted
and is used as a key to extract the correct coordinates of the port to display and to be used by buswire.fs. Since the `APortOffsetMap` is updated
at every rotation (discussed in later extensions), `getGlobalPortPos` will always receive a new `APortOffsetMap` at every orientation and thus
not require the current orientation as input. This can be tested by rotating a symbol and connecting another symbol's ports to its ports.
It can be observed that the gray circles used to distinguish which ports connection can be made are correctly displayed on the rotated symbol, and
the buswire correctly connects to that rotated port location. However, two issues seem to arise. The wire is connected parallel to the
port, if the symbol is rotated as the `buswire.fs` is expecting the symbol to be non-rotated. Additionally, the `buswire.fs` seems to only
update when the symbol is moved. As a result, a communication between the rotations and orientations of the symbol need to be passed
to `buswire.fs` to ensure that the wires are correctly displayed during rotation. This will be done later on in the group work.
$baseMark = \min (70, code * 20/35 + analysis * 15/35)$
## 2. UI to rotate symbol
### Changes in files:
- __Symbol.fs__
- `1164-1173` RotateSymbols compList
$extendedMark = code * 20/50 + analysis * 15/50 + extensions * 15/50$
$overallMark = \max (baseMark, extendedMark)$
* This section can be missing if you have not done significant extension work.
* Extension code, if well documented (in the code) and clearly written, can be assessed without working
(if it is demonstrated it depends on other people's code not yet written).
* Don't bother writing this section unless you have significant extension work, because the mark here
will usually not be counted in that case (see the marking scheme). Marks for extensions will be awarded
only for work of C level or above.
* delete the above comemnts and add your satement of extensions as below*
1. List as numbered points the extensions (features) your code will support
a. Use nested letters for the functions you have written extra,
or changed, to allow this, and for concise comments concise comments about why they work.
- __Sheet.fs__
- `86` Type KeyboardMsg Rotate
- `859-863` Keypress Rotate
- __Renderer.fs__
- `151-152` makeItem "Rotate Symbol"
### Explanation:
The UI was altered to incorporate the use of symbol rotation. Thus was done by first altering the `Renderer.fs`. Line 151 was added
to add the menu item "Rotate Symbol" in order to be able to rotate any symbol selected. This option was then linked through `Sheet.fs`
This functionality can be found on the menu bar under "View". Further implementation was added to rotation by adding a keyboard shortcut.
This was done in line 86 of `Sheet.fs` where the KeybrdMsg "Rotate" was added to implement this. Lines 859-863 were added to link
the menu item and keyboard shortcut "Shift+R" to Symbol.RotateSymbols in `Symbol.fs` to rotate the symbol selected.
The case "RotateSymbols" was added to the "update" function used in `Symbol.fs` to update the symbols on the canvas. As seen in lines
"1164-1173" a new map of symbols, to be displayed and were existing on the canvas, is created where the symbol with the specified id
found after being seelcted, is changed by incrementing its STransform value to the next Rotation using stransform_fsm and
updating the `APortOffsetMap` using RotatePortMap provided by Section 1. Finally, the model Symbols are replaced by these new symbols.
As a result, the selected symbol is updated with its 90 deg rotated version. Worth noting is the addition of the `canvasPortLocation`
function in this case to print the global port locations as explained previously.
The above can be fully tested by selecting a symbol on the canvas and pressing either `Shift+R` or `View > Rotate Symbol`.
The "Global" port coordinates of the selected symbol will also appear in the console if Developer Tools are toggled on.
### 3. Make symbol bounding box work with rotation
### Changes in files:
- __Symbol.fs__
- `724-727` getBoundingBoxofSymbol
- `728-729` getBoundingBoxes
- `730-731` getOneBoundingBox
### Explanation:
The function `getBoundingBoxofSymbol` was updated to correctly alter the bounding box border of each symbol by taking into account
the current orientation of the symbol. This is done using the STransform passed from the Symbol as input of the function. This is
used as a match case where the bounding box is altered as `HxW` and `WxH` based on the current orientation of the symbol.
The height and weight of the symbol are passed to the border width and height in order or in reverse. This ensures that for every orientation
of the symbol, the correct border is used. The new `getBoundingBoxofSymbol` function is passed to the `getBoundingBoxes` and `getOneBoundingBox`
to be used by `Sheet.fs` to correctly display the Bounding box of the symbol at each orientation.
This can be tested by selecting the symbol to be tested, then rotated and checking with another symbol whether the bounding box
correctly responds when disrupted.
The Symbol enhancements for section 2 described above are fully working without producing any errors during build and runtime

View file

@ -101,8 +101,8 @@ let stransform_fsm(prev_state:Rotation):Rotation =
| R180 -> R270
| R270 -> R0
///Insert titles compatible with greater than 1 buswidth
let title t (n) =
///Insert titles compatible with greater than 1 bus width
let title t n =
if n = 1 then t else t + "(" + string(n-1) + "..0)"
///Insert titles for bus select
@ -150,13 +150,13 @@ let gateDecoderType (comp:Component) =
| AsyncRAM1 _ -> "Async-RAM"
| DFF -> "DFF"
| DFFE -> "DFFE"
| NbitsXor (x)-> title "N-bits-Xor" x
| NbitsXor x-> title "N-bits-Xor" x
| Custom x -> x.Name
| _ -> ""
let createCustomPortNamesMap inputLabels outputLabels =
let adder x ((name:string),n) (portType:PortType)=
let adder x (name:string,_) (portType:PortType) =
let key =
match portType with
|PortType.Input -> "I"+ string x
@ -241,31 +241,31 @@ let makeComp (pos: XYPos) (comptype: ComponentType) (id:string) (label:string) :
failwithf "What? Legacy RAM component types should never occur"
| And | Nand | Or | Nor | Xnor | Xor -> (2 , 1, 2*GridSize , 2*GridSize)
| Not -> ( 1 , 1, 2*GridSize , 2*GridSize)
| ComponentType.Input (a) -> ( 0 , 1, GridSize , 2*GridSize)
| ComponentType.Output (a) -> ( 1 , 0, GridSize , 2*GridSize)
| ComponentType.Viewer a -> ( 1 , 0, GridSize , GridSize)
| ComponentType.Input _ -> ( 0 , 1, GridSize , 2*GridSize)
| ComponentType.Output _ -> ( 1 , 0, GridSize , 2*GridSize)
| ComponentType.Viewer _ -> ( 1 , 0, GridSize , GridSize)
| ComponentType.IOLabel ->( 1 , 1, GridSize , 2*GridSize)
| Decode4 ->( 2 , 4 , 4*GridSize , 3*GridSize)
| Constant1 (a, b,_) | Constant(a, b) -> ( 0 , 1, GridSize , 2*GridSize)
| Constant1 _ | Constant _ -> ( 0 , 1, GridSize , 2*GridSize)
| MergeWires -> ( 2 , 1, 2*GridSize , 2*GridSize)
| SplitWire (a) ->( 1 , 2 , 2*GridSize , 2*GridSize)
| SplitWire _ ->( 1 , 2 , 2*GridSize , 2*GridSize)
| Mux2 -> ( 3 , 1, 3*GridSize , 2*GridSize)
// EXTENSION: | Mux4 -> ( 5 , 1, 5*GridSize , 2*GridSize)
// EXTENSION: | Mux8 -> ( 9 , 1, 7*GridSize , 2*GridSize)
| Demux2 ->( 2 , 2, 3*GridSize , 2*GridSize)
// EXTENSION: | Demux4 -> ( 2 , 4, 150 , 50)
// EXTENSION: | Demux8 -> ( 2 , 8, 200 , 50)
| BusSelection (a, b) -> ( 1 , 1, GridSize, 2*GridSize)
| BusCompare (a, b) -> ( 1 , 1, GridSize , 2*GridSize)
| BusSelection _ -> ( 1 , 1, GridSize, 2*GridSize)
| BusCompare _ -> ( 1 , 1, GridSize , 2*GridSize)
| DFF -> ( 1 , 1, 3*GridSize , 3*GridSize)
| DFFE -> ( 2 , 1, 3*GridSize , 3*GridSize)
| Register (a) -> ( 1 , 1, 3*GridSize , 4*GridSize )
| RegisterE (a) -> ( 2 , 1, 3*GridSize , 4*GridSize)
| AsyncROM1 (a) -> ( 1 , 1, 3*GridSize , 4*GridSize)
| ROM1 (a) -> ( 1 , 1, 3*GridSize , 4*GridSize)
| RAM1 (a) | AsyncRAM1 a -> ( 3 , 1, 3*GridSize , 4*GridSize)
| NbitsXor (n) -> ( 2 , 1, 3*GridSize , 4*GridSize)
| NbitsAdder (n) -> ( 3 , 2, 3*GridSize , 4*GridSize)
| Register _ -> ( 1 , 1, 3*GridSize , 4*GridSize )
| RegisterE _ -> ( 2 , 1, 3*GridSize , 4*GridSize)
| AsyncROM1 _ -> ( 1 , 1, 3*GridSize , 4*GridSize)
| ROM1 _ -> ( 1 , 1, 3*GridSize , 4*GridSize)
| RAM1 _ | AsyncRAM1 _ -> ( 3 , 1, 3*GridSize , 4*GridSize)
| NbitsXor _ -> ( 2 , 1, 3*GridSize , 4*GridSize)
| NbitsAdder _ -> ( 3 , 2, 3*GridSize , 4*GridSize)
| Custom x ->
let h = GridSize + GridSize * (List.max [List.length x.InputLabels; List.length x.OutputLabels])
let maxInLength, maxOutLength = customToLength x.InputLabels, customToLength x.OutputLabels
@ -315,8 +315,8 @@ let inline getPortPosEdgeGap (ct: ComponentType) =
| _ -> 1.0
let getPortPos (comp: Component) (port:Port) =
let (ports, posX) =
if port.PortType = (PortType.Input) then
let ports, posX =
if port.PortType = PortType.Input then
(comp.InputPorts, 0.0)
else
(comp.OutputPorts, float( comp.W ))
@ -341,8 +341,8 @@ let offsethelper (comp: Component) orientation (port:Port) =
match ct with
| MergeWires | SplitWire _ -> 0.25
| _ -> 1.0
let (ports, posX) =
if port.PortType = (PortType.Input) then
let ports, posX =
if port.PortType = PortType.Input then
(comp.InputPorts, 0.0)
else
(comp.OutputPorts, float( comp.W ))
@ -354,7 +354,7 @@ let offsethelper (comp: Component) orientation (port:Port) =
/////change name
let portListToMap (portList: Port List) (symbol: Symbol) : Map<string,PortOrientationOffset>=
let adder (symbol: Symbol) (port: Port) =
let num = match port.PortNumber with |Some n -> n |_->(-1)
let num = match port.PortNumber with |Some n -> n |_-> -1
let key =
match port.PortType with
|PortType.Input -> "I"+ string num
@ -643,9 +643,9 @@ let compSymbol (symbol:Symbol) (comp:Component) (colour:string) (showInputPorts:
| ROM1 _ |RAM1 _ | AsyncRAM1 _ -> (addClock 0 h colour opacity)
| BusSelection(x,y) -> (addText (float(wR/2)-5.0) ((float(hR)/2.7)-2.0) (bustitle x y) "middle" "normal" "12px")
| BusCompare (_,y) -> (addText (float(wR/2)-6.0) (float(hR)/2.7-1.0) ("=" + NumberHelpers.hex(int y)) "middle" "bold" "10px")
| Input (x) -> (addText (float(wR/2)) ((float(hR)/3.0)) (title "" x) "middle" "normal" "12px")
| Output (x) -> (addText (float(wR/2)) ((float(hR)/3.0)) (title "" x) "middle" "normal" "12px")
| Viewer (x) -> (addText (float(w/2)) ((float(h)/2.7)-1.25) (title "" x) "middle" "normal" "9px")
| Input x -> (addText (float(wR/2)) ((float(hR)/3.0)) (title "" x) "middle" "normal" "12px")
| Output x -> (addText (float(wR/2)) ((float(hR)/3.0)) (title "" x) "middle" "normal" "12px")
| Viewer x -> (addText (float(w/2)) ((float(h)/2.7)-1.25) (title "" x) "middle" "normal" "9px")
| _ -> []
let olColour, strokeWidth =
@ -714,6 +714,11 @@ let view (model : Model) (dispatch : Msg -> unit) =
|> TimeHelpers.instrumentInterval "SymbolView" start
//---------------------------------------------------------------------------------//
//--------------------GV319 CODE SECTION 2 STARTS-------------------------------------//
//---------------------------------------------------------------------------------//
//------------------------GET BOUNDING BOXES FUNCS--------------------------------used by sheet.
// Function that returns the bounding box of a symbol. It is defined by the height and the width as well as the x,y position of the symbol
let getBoundingBoxofSymbol (sym:Symbol): BoundingBox =
@ -721,8 +726,7 @@ let getBoundingBoxofSymbol (sym:Symbol): BoundingBox =
| R0 | R180 -> {X = float(sym.Pos.X) ; Y = float(sym.Pos.Y) ; H = float(sym.Compo.H) ; W = float(sym.Compo.W)}
| R90 | R270 -> {X = float(sym.Pos.X) ; Y = float(sym.Pos.Y) ; H = float(sym.Compo.W) ; W = float(sym.Compo.H)}
let getBoundingBoxes (symModel: Model): Map<ComponentId, BoundingBox> =
Map.map (fun sId (sym:Symbol) -> (getBoundingBoxofSymbol sym)) symModel.Symbols
Map.map (fun _ (sym:Symbol) -> (getBoundingBoxofSymbol sym)) symModel.Symbols
let getOneBoundingBox (symModel: Model) (compid: ComponentId ): BoundingBox =
getBoundingBoxofSymbol (Map.find compid symModel.Symbols)
@ -736,43 +740,39 @@ let getSymbolPos (symbolModel: Model) compId =
// Function to generate Port Positions of each port from Symbol Location and Orientation
// Input: Symbol -> Take the symbol for which to extract positions of ports
// Output: XYPos list -> Return a list of XYPos positions of the ports starting from inputs, anticlockwise.
let canvasPortLocation (sym:Symbol) : XYPos list =
let canvasPortLocation (sym:Symbol) : XYPos list =
sym.APortOffsetsMap
|> Map.toList
|> List.map snd
|> List.map (fun prevCoor -> prevCoor.Offset)
|> List.map (fun i -> i.Offset)
|> List.map (fun i -> {X=i.X+sym.Pos.X;Y=i.Y + sym.Pos.Y})
// Function to generate the true XYPos of a specified Port on the Canvas given the port and symbol
// Input: Symbol, Port -> Take the symbol and the specified port
// Output: XYPos-> Return the XYPos position of the ports depending on being inputs or outputs
let getGlobalPortPos (sym: Symbol) (port:Port) :XYPos =
let (typePort,ports) =
if port.PortType = (PortType.Input) then
let typePort,ports =
if port.PortType = PortType.Input then
("I",sym.Compo.InputPorts)
else
("O",sym.Compo.OutputPorts)
let index = float( List.findIndex (fun (p:Port) -> p = port) ports )
(Map.find (typePort + string index) sym.APortOffsetsMap).Offset
let getGlobalPortPosModel (sym: Symbol) (port:Port) =
getGlobalPortPos sym port
///
///
let getInputPortsPositionMap (model: Model) (symbols: Symbol list) =
/// It is used in getInputPortLocation for a single port
let getInputPortsPositionMap (symbols: Symbol list) =
symbols
|> List.collect (fun sym -> List.map (fun p -> sym,p) sym.Compo.InputPorts)
|> List.map (fun (sym,port) -> (InputPortId port.Id, posAdd (getGlobalPortPosModel sym port) (sym.Pos)))
|> List.map (fun (sym,port) -> (InputPortId port.Id, posAdd (getGlobalPortPos sym port) sym.Pos))
|> Map.ofList
/// This is quite slow, because it gets the whole maps.
/// It is used in getOutputPortLocation for a single port!!
/// Bad
let getOutputPortsPositionMap (model: Model) (symbols: Symbol list) = //These function add the coordinates of the symbol too
/// It is used in getOutputPortLocation for a single port
let getOutputPortsPositionMap (symbols: Symbol list) =
symbols
|> List.collect (fun sym -> List.map (fun p -> sym,p) sym.Compo.OutputPorts)
|> List.map (fun (sym,port) -> (OutputPortId port.Id , posAdd (getGlobalPortPosModel sym port) (sym.Pos)))
|> List.map (fun (sym,port) -> (OutputPortId port.Id , posAdd (getGlobalPortPos sym port) sym.Pos))
|> Map.ofList
///Returns the port object associated with a given portId
@ -783,12 +783,12 @@ let getPort (symModel: Model) (portId: string) =
let getPortLocations (symbolModel: Model) (sIds: ComponentId list) =
let getSymbols =
symbolModel.Symbols
|> Map.filter (fun sId sym -> List.contains sId sIds)
|> Map.filter (fun sId _ -> List.contains sId sIds)
|> Map.toList
|> List.map snd
let getInputPortMap = getInputPortsPositionMap symbolModel getSymbols
let getOutputPortMap = getOutputPortsPositionMap symbolModel getSymbols
let getInputPortMap = getInputPortsPositionMap getSymbols
let getOutputPortMap = getOutputPortsPositionMap getSymbols
getInputPortMap , getOutputPortMap
@ -799,8 +799,8 @@ let getInputPortLocation (model:Model) (portId: InputPortId) =
|> Map.toList
|> List.map snd
getInputPortsPositionMap model allSymbols
|> Map.find (portId)
getInputPortsPositionMap allSymbols
|> Map.find portId
//Returns the location of an output portId
@ -810,8 +810,8 @@ let getOutputPortLocation (model:Model) (portId : OutputPortId) =
|> Map.toList
|> List.map snd
getOutputPortsPositionMap model allSymbols
|> Map.find (portId)
getOutputPortsPositionMap allSymbols
|> Map.find portId
///Returns the location of a given portId
let getOnePortLocation (symModel: Model) (portId : string) (pType: PortType)=
@ -819,19 +819,18 @@ let getOnePortLocation (symModel: Model) (portId : string) (pType: PortType)=
| PortType.Input ->
getInputPortLocation symModel (InputPortId portId)
| PortType.Output ->
getOutputPortLocation symModel (OutputPortId portId)
getOutputPortLocation symModel (OutputPortId portId)
/// Returns the location of a given portId, with better efficiency
/// This is still slow, the ports should be looked up from a map of ports
let getOnePortLocationNew (symModel: Model) (portId : string) (pType: PortType) : XYPos=
let getOnePortLocationNew (symModel: Model) (portId : string) (pType: PortType) : XYPos =
symModel.Symbols
|> Map.pick (fun key sym ->
|> Map.pick (fun _ sym ->
let comp = sym.Compo
if pType = PortType.Input then
List.tryFind (fun (po:Port) -> po.Id = portId) comp.InputPorts
else
List.tryFind (fun (po:Port) -> po.Id = portId) comp.OutputPorts
|> Option.map (fun port -> posAdd (getGlobalPortPosModel sym port) (sym.Pos)))
|> Option.map (fun port -> posAdd (getGlobalPortPos sym port) sym.Pos))
/// Returns the locations of a given input portId and output portId
@ -841,7 +840,7 @@ let getTwoPortLocations (symModel: Model) (inPortId: InputPortId ) (outPortId: O
(getOnePortLocationNew symModel inputId PortType.Input, getOnePortLocationNew symModel outputId PortType.Output)
/// Interface function to get componentIds of the copied symbols
let getCopiedSymbols (symModel: Model) : (ComponentId list) =
let getCopiedSymbols (symModel: Model) : ComponentId list =
symModel.CopiedSymbols
|> Map.toList
|> List.map fst
@ -976,7 +975,7 @@ let getIndex listSymbols compType =
|> (+) 1
|> string
///Generates the number to be put in the title of symbols
///Generates the number to be put in the title of symbols
let labelGenNumber (model: Model) (compType: ComponentType) (label : string) =
let listSymbols = List.map snd (Map.toList model.Symbols)
match compType with
@ -989,7 +988,7 @@ let generateLabel (model: Model) (compType: ComponentType) : string =
/// Interface function to paste symbols. Is a function instead of a message because we want an output
/// Currently drag-and-drop
let pasteSymbols (symModel: Model) (mPos: XYPos) : (Model * ComponentId list) =
let pasteSymbols (symModel: Model) (mPos: XYPos) : Model * ComponentId list =
let createNewSymbol (basePos: XYPos) ((currSymbolModel, pastedIdsList) : Model * ComponentId List) (oldSymbol: Symbol): Model * ComponentId List =
let newId = JSHelpers.uuid()
let posDiff = posDiff oldSymbol.Pos basePos
@ -1019,11 +1018,11 @@ let pasteSymbols (symModel: Model) (mPos: XYPos) : (Model * ComponentId list) =
((symModel, []), oldSymbolsList) ||> List.fold (createNewSymbol basePos)
| [] -> symModel, []
/// Given two componentId list of same length and input / output ports that are in list 1, return the equivalent ports in list 2.
/// ComponentIds at same index in both list 1 and list 2 need to be of the same ComponentType
/// CompIds1 need to be in model.CopiedSymbols
let getEquivalentCopiedPorts (model: Model) (copiedIds) (pastedIds) (InputPortId copiedInputPort, OutputPortId copiedOutputPort) =
let getEquivalentCopiedPorts (model: Model) copiedIds pastedIds (InputPortId copiedInputPort, OutputPortId copiedOutputPort) =
let findEquivalentPorts compId1 compId2 =
let copiedComponent = model.CopiedSymbols[compId1].Compo
let pastedComponent = model.Symbols[compId2].Compo // TODO: These can be different for an output gate for some reason.
@ -1087,7 +1086,7 @@ let changeNumberOfBitsf (symModel:Model) (compId:ComponentId) (newBits : int) =
{symbol with Compo = newcompo}
// Helper function to change the number of bits expected in the LSB port of BusSelection and BusCompare
let changeLsbf (symModel:Model) (compId:ComponentId) (newLsb:int64) =
let changeLSBbits (symModel:Model) (compId:ComponentId) (newLsb:int64) =
let symbol = Map.find compId symModel.Symbols
let newcompotype =
match symbol.Compo.Type with
@ -1098,7 +1097,8 @@ let changeLsbf (symModel:Model) (compId:ComponentId) (newLsb:int64) =
let newcompo = {symbol.Compo with Type = newcompotype}
{symbol with Compo = newcompo}
let changeConstantf (symModel:Model) (compId:ComponentId) (constantVal:int64) (constantText: string) =
// Helper function to change the name and value of a Constant Symbol
let changeConstant (symModel:Model) (compId:ComponentId) (constantVal:int64) (constantText: string) =
let symbol = Map.find compId symModel.Symbols
let newcompotype =
match symbol.Compo.Type with
@ -1116,7 +1116,7 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> =
{ model with Symbols = newSymbols }, Cmd.none //filters out symbol with a specified id
| AddSymbol (pos,compType, lbl) ->
let (newModel, _) = addSymbol model pos compType lbl
let newModel, _ = addSymbol model pos compType lbl
newModel, Cmd.none
| CopySymbols compIds ->
@ -1159,15 +1159,16 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> =
let resetSymbols = Map.map (fun _ sym -> { sym with Colour = "Lightgray"; Opacity = 1.0 }) model.Symbols
let newSymbols =
(List.fold (fun prevSymbols sId -> Map.add sId {resetSymbols[sId] with Colour = "lightgreen"} prevSymbols) resetSymbols compList)
{ model with Symbols = newSymbols }, Cmd.none
{ model with Symbols = newSymbols }, Cmd.none
| RotateSymbols compList -> //select a symbol to Rotate
| RotateSymbols compList -> // NEW: select a symbol to Rotate
let resetSymbols = Map.map (fun _ sym -> { sym with Colour = "Lightgray"; Opacity = 1.0 }) model.Symbols
let newSymbols =
// if ctrl is pressed make yellow initially, then try to change STransform for every time ctrl+R is pressed
let newSymbols =
// The selected symbol is rotated by incrementing Stransform rotation and updating new APortOffsetsMap and Symbol Pos
List.fold (fun prevSymbols sId ->
Map.add sId {model.Symbols[sId] with STransform = stransform_fsm(model.Symbols[sId].STransform); APortOffsetsMap = rotatePortMap model.Symbols[sId].APortOffsetsMap model.Symbols[sId]} prevSymbols) resetSymbols compList
let result = (canvasPortLocation(model.Symbols[compList[0]]))
//Used to print it Dev Tools Terminal list of ports global coordinates starting anticlockwise from inputs
printf "%A" result
{ model with Symbols = newSymbols }, Cmd.none
@ -1209,13 +1210,13 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> =
{ model with Symbols = newSymbolsWithChangedSymbol }, Cmd.none
| ChangeLsb (compId, newLsb) ->
let newsymbol = changeLsbf model compId newLsb
let newsymbol = changeLSBbits model compId newLsb
let symbolswithoutone = model.Symbols.Remove compId
let newSymbolsWithChangedSymbol = symbolswithoutone.Add (compId, newsymbol)
{ model with Symbols = newSymbolsWithChangedSymbol }, Cmd.none
| ChangeConstant (compId, newVal, newText) ->
let newsymbol = changeConstantf model compId newVal newText
let newsymbol = changeConstant model compId newVal newText
let symbolswithoutone = model.Symbols.Remove compId
let newSymbolsWithChangedSymbol = symbolswithoutone.Add (compId, newsymbol)
{ model with Symbols = newSymbolsWithChangedSymbol }, Cmd.none
@ -1227,7 +1228,7 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> =
comps
|> List.map ( fun comp -> (
let xyPos = {X = float comp.X; Y = float comp.Y}
let (h,w) =
let h,w =
if comp.H = -1 && comp.W = -1 then
let comp' = makeComp xyPos comp.Type comp.Id comp.Label
comp'.H,comp'.W
@ -1284,9 +1285,9 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> =
let comp = symbol.Compo
let newCompType =
match comp.Type with
| RAM1 mem | AsyncRAM1 mem -> memory
| ROM1 mem -> memory
| AsyncROM1 mem -> memory
| RAM1 _ | AsyncRAM1 _ -> memory
| ROM1 _ -> memory
| AsyncROM1 _ -> memory
| _ ->
printfn $"Warning: improper use of WriteMemoryType on {comp} ignored"
comp.Type
@ -1305,3 +1306,6 @@ let extractComponents (symModel: Model) : Component list =
symModel.Symbols
|> Map.toList
|> List.map (fun (key, _) -> extractComponent symModel key)
//---------------------------------------------------------------------------------//
//--------------------GV319 CODE SECTION 2 ENDS-------------------------------------//
//---------------------------------------------------------------------------------//