Inital Commit. Mostly working

This commit is contained in:
2020-12-24 16:37:28 +01:00
commit 98bd366c24
12 changed files with 8694 additions and 0 deletions

660
src/Main.elm Normal file
View File

@ -0,0 +1,660 @@
--module Main exposing (Model, Msg, update, view, init)
port module Main exposing (..)
import Browser
import Html exposing (Html, button, div, h1, p, text)
import Html.Attributes as HAttr exposing (class, classList, value)
import Html.Events exposing (onClick)
import Html.Lazy exposing (lazy)
import Tuple
import Array exposing (get)
-- Note that general Stuff is at the end of the document
-- PORTS
port sendUUpdate : String -> Cmd msg
port sendRamUpdate : String -> Cmd msg
port recieveLocalSession : (String -> msg) -> Sub msg
type alias PC =
{ ram : List Int
, dataBus : Int
, addressBus : Int
, instructionReg : Int
, programmCounter : Int
, uCounter : Int
, accumulator : Int
}
type alias Model =
{ pc : PC
, uCode : List (Maybe UAction)
, autoscroll : Bool
}
type UAction
= ActAccumulator2DataBus
| ActAccumulatorDecrement
| ActAccumulatorIncrement
| ActDataBus2Accumulator
| ActDataBus2InstructionReg
| ActDataBus2Ram
| ActInstructionReg2AddressBus
| ActInstructionReg2ProgrammCounter
| ActInstructionReg2UCounter
| ActProgrammCounterIncrement
| ActRam2DataBus
| ActResetUCounter
| ActProgrammCounter2AddressBus
uCodeDescriptions : List ( UAction, String )
uCodeDescriptions =
[ ( ActAccumulator2DataBus, "Acc -> DataBus" )
, ( ActAccumulatorDecrement, "Acc --" )
, ( ActAccumulatorIncrement, "Acc ++" )
, ( ActDataBus2Accumulator, "DataBus -> Acc" )
, ( ActDataBus2InstructionReg, "DataBus -> InstReg" )
, ( ActDataBus2Ram, "DataBus -> Ram" )
, ( ActInstructionReg2AddressBus, "InstReg -> AddrBus" )
, ( ActInstructionReg2ProgrammCounter, "InstReg -> ProgCount" )
, ( ActInstructionReg2UCounter, "InstReg -> µCounter" )
, ( ActProgrammCounterIncrement, "ProgCounter ++" )
, ( ActRam2DataBus, "Ram -> DataBus" )
, ( ActResetUCounter, "µCounter = 0" )
, ( ActProgrammCounter2AddressBus, "ProgCounter -> AddrBus" )
]
uCodeMaps : List ( UAction, PC -> PC )
uCodeMaps =
[ ( ActAccumulator2DataBus, actAccumulator2DataBus )
, ( ActAccumulatorDecrement, actAccumulatorDecrement )
, ( ActAccumulatorIncrement, actAccumulatorIncrement )
, ( ActDataBus2Accumulator, actDataBus2Accumulator )
, ( ActDataBus2InstructionReg, actDataBus2InstructionReg )
, ( ActDataBus2Ram, actDataBus2Ram )
, ( ActInstructionReg2AddressBus, actInstructionReg2AddressBus )
, ( ActInstructionReg2ProgrammCounter, actInstructionReg2ProgrammCounter )
, ( ActInstructionReg2UCounter, actInstructionReg2UCounter )
, ( ActProgrammCounterIncrement, actProgrammCounterIncrement )
, ( ActRam2DataBus, actRam2DataBus )
, ( ActResetUCounter, actResetUCounter )
, ( ActProgrammCounter2AddressBus, actProgrammCounter2AddressBus )
]
initialRam : List Int
initialRam =
[ 100005 -- 000 -- LoadA #005
, 300000 -- 001 -- IncA
, 200005 -- 002 -- StoreA #005
, 400000 -- 003 -- JMP #000
, 0 -- 004
, 5 -- 005
, 0 -- 006
, 0 -- 007
, 0 -- 008
, 0 -- 009
, 0 -- 010
]
initialPC : PC
initialPC =
PC
initialRam
0
0
0
0
0
0
initialUCodes : List (Maybe UAction)
initialUCodes =
[ Just ActProgrammCounter2AddressBus -- 000
, Just ActRam2DataBus -- 001
, Just ActDataBus2InstructionReg -- 002
, Just ActProgrammCounterIncrement -- 003
, Just ActInstructionReg2UCounter -- 004
, Nothing -- 005
, Nothing
, Nothing
, Nothing
, Nothing -- 009
-- 010 LOADA
, Just ActInstructionReg2AddressBus -- 010
, Just ActRam2DataBus -- 011
, Just ActDataBus2Accumulator -- 012
, Just ActResetUCounter -- 013
, Nothing -- 014
, Nothing
, Nothing
, Nothing
, Nothing
, Nothing -- 019
-- 020 STOA
, Just ActAccumulator2DataBus -- 020
, Just ActInstructionReg2AddressBus -- 021
, Just ActDataBus2Ram -- 022
, Just ActResetUCounter -- 023
, Nothing --024
, Nothing
, Nothing
, Nothing
, Nothing
, Nothing -- 029
-- 030 INCA
, Just ActAccumulatorIncrement -- 030
, Just ActResetUCounter -- 031
, Nothing -- 032
, Nothing
, Nothing
, Nothing
, Nothing
, Nothing
, Nothing
, Nothing -- 039
-- 040 JMP
, Just ActInstructionReg2ProgrammCounter -- 040
, Just ActResetUCounter -- 041
, Nothing -- 042
, Nothing
, Nothing
, Nothing
, Nothing
, Nothing
, Nothing
, Nothing -- 049
]
type Msg
= MsgUCycleStep
| MsgInstructionStep
| MsgReset
| MsgAutoscrollUpdate
| MsgManualStep UAction
| MsgLocalSessionRecieve String
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
MsgUCycleStep ->
( uStepPC model
, sendUUpdate "uCycle updated"
)
MsgInstructionStep ->
( model, Cmd.none )
MsgReset ->
( { model | pc = { initialPC | ram = model.pc.ram } }
, Cmd.none
)
MsgLocalSessionRecieve message_in ->
( model, Cmd.none )
MsgManualStep action ->
let
instruction = getAction action
in
( { model | pc = instruction model.pc}
, Cmd.none )
MsgAutoscrollUpdate ->
( { model | autoscroll = not model.autoscroll }
, Cmd.none
)
-- Practically a part of uStepPC but sepeated for manual mode
getAction : UAction -> (PC -> PC)
getAction uAction =
let
possible_instructions =
List.filter (\s -> Tuple.first s == uAction) uCodeMaps
in
case List.head possible_instructions of
Just ( name, instruction ) ->
instruction
_ ->
(\s -> s)
uStepPC : Model -> Model
uStepPC model =
let
uCounter =
model.pc.uCounter
may_instruction : Maybe (Maybe UAction)
may_instruction =
valueAt uCounter model.uCode
in
case may_instruction of
Just (Just action) ->
let
possible_instructions =
List.filter (\s -> Tuple.first s == action) uCodeMaps
in
case List.head possible_instructions of
Just ( name, instruction ) ->
let
old_pc =
model.pc
new_pc =
{ old_pc | uCounter = old_pc.uCounter + 1 }
in
{ model | pc = instruction new_pc }
_ ->
let
old_pc =
model.pc
new_pc =
{ old_pc | uCounter = 0 }
in
{ model | pc = new_pc }
_ ->
model
view : Model -> Html Msg
view model =
lazy viewPC model
viewPC : Model -> Html Msg
viewPC model =
div
[ class "pc" ]
[ div [ class "controls", class "grid-fullwidth" ]
[ button [ onClick MsgUCycleStep ] [ text "µZyklus" ]
, button [ onClick MsgInstructionStep ] [ text "Instruction" ]
, button [ onClick MsgReset ] [ text "Reset PC" ]
, div
[ classList
[ ("checker", True)
, ("button", True)
, ("checked", model.autoscroll) ]
, onClick MsgAutoscrollUpdate
]
[ Html.input
[ HAttr.type_ "checkbox"
, HAttr.id "enableScrolling"
, HAttr.checked model.autoscroll
, onClick MsgAutoscrollUpdate
]
[]
, Html.label
[ HAttr.for "enableScrolling" ]
[ text "Automatisch zum Eintrag Scrollen" ]
]
]
, div [ class "grid-fullwidth" ] [ lazy viewAddressBus model ]
, lazy viewRam model
, lazy viewCu model
, lazy viewAlu model
, div [ class "grid-fullwidth" ] [ lazy viewDataBus model ]
]
viewRam : Model -> Html Msg
viewRam model =
div [ class "section", class "ram" ]
[ h1 [ class "header" ] [ text "RAM" ]
, div [ class "arrow", class "down", class "top"] [ div [] [] , div [] [] ]
, div [ class "scroller" ]
[ Html.table [ class "" ]
[ Html.thead [ class "head" ]
[ Html.tr []
[ Html.th [ class "address" ] [ text "Addr" ]
, Html.th [] [ text "Value" ]
]
]
, lazy viewRamContent model
]
]
, div [ class "arrow", class "down"]
[ div [ class "button" ]
[ Html.a [ onClick (MsgManualStep ActRam2DataBus) ] [ text "Ram -> DataBus" ]]
, div [] []
]
, div [ class "arrow", class "up"]
[ div [ class "button" ]
[ Html.a [ onClick (MsgManualStep ActDataBus2Ram) ] [ text "DataBus -> Ram" ]]
, div [] []
]
]
viewRamContent : Model -> Html Msg
viewRamContent model =
let
indexedRam =
List.indexedMap Tuple.pair model.pc.ram
ram2table : ( Int, Int ) -> Html Msg
ram2table entry =
let
id =
Tuple.first entry
val =
Tuple.second entry
in
Html.tr
[ classList [ ( "current", id == model.pc.addressBus ) ] ]
[ Html.td [ class "num" ] [ text (String.fromInt id) ]
, Html.td [ class "num " ] [ text (String.fromInt val) ]
]
in
Html.tbody [] (List.map ram2table indexedRam)
viewCu : Model -> Html Msg
viewCu model =
div [ class "section", class "cu" ]
[ div [ class "arrow", class "up", class "top"]
[ div [ class "button" ]
[ Html.a [ onClick (MsgManualStep ActInstructionReg2AddressBus)] [ text "InstR -> AddrB" ]]
, div [] []
]
, h1 [ class "header" ] [ text "Control Unit" ]
, p []
[ text
("Programm Counter: "
++ String.fromInt model.pc.programmCounter
)
]
, p []
[ text
("Instruction Register: "
++ String.fromInt model.pc.instructionReg
)
]
, p []
[ text
("µCode Counter: "
++ String.fromInt model.pc.uCounter
)
]
, div [ class "scroller" ]
[ viewCuUCode model
]
, div [ class "arrow", class "up"]
[ div [ class "button" ]
[ Html.a [ onClick (MsgManualStep ActDataBus2InstructionReg) ] [ text "DB -> InstR" ]]
, div [] []
]
]
viewCuUCode : Model -> Html Msg
viewCuUCode model =
Html.table []
[ Html.thead [ class "head" ]
[ Html.tr []
[ Html.th [ class "address" ] [ text "Addr" ]
, Html.th [] [ text "Code" ]
]
]
, lazy viewCuUCodeContent model
]
viewCuUCodeContent : Model -> Html Msg
viewCuUCodeContent model =
let
indexedList =
List.indexedMap Tuple.pair model.uCode
list2table : ( Int, Maybe UAction ) -> Html Msg
list2table may_t =
let
id =
Tuple.first may_t
may_code =
Tuple.second may_t
in
case may_code of
Just code ->
let
possibleDescriptions : List ( UAction, String )
possibleDescriptions =
List.filter (\s -> Tuple.first s == code) uCodeDescriptions
codeDescription =
case List.head possibleDescriptions of
Just ( _, description ) ->
description
_ ->
"Idk what this is"
in
Html.tr
[ classList [ ( "current", id == model.pc.uCounter ) ] ]
[ Html.td [ class "num" ] [ text (String.fromInt id) ]
, Html.td [] [ text codeDescription ]
]
Nothing ->
Html.tr [ class "empty" ]
[ Html.td [ class "num" ] [ text (String.fromInt id) ]
, Html.td [] [ text "Empty" ]
]
in
Html.tbody [] (List.map list2table indexedList)
viewAlu : Model -> Html Msg
viewAlu model =
div [ class "section", class "alu" ]
[ h1 [ class "header" ] [ text "ALU" ]
, p [] [ text ("Accumulator: " ++ String.fromInt model.pc.accumulator) ]
, div [ class "arrow", class "up"]
[ div [ class "button" ]
[ Html.a [ onClick (MsgManualStep ActDataBus2Accumulator)] [ text "DB -> ALU" ]]
, div [] []
]
, div [ class "arrow", class "down"]
[ div [ class "button" ]
[ Html.a [ onClick (MsgManualStep ActAccumulator2DataBus)] [ text "ALU -> DB" ]]
, div [] []
]
]
viewDataBus : Model -> Html Msg
viewDataBus model =
div [ class "databus" ]
[ Html.span [ class "label" ] [ text "Databus" ]
, Html.span [] [ text (String.fromInt model.pc.dataBus) ]
]
viewAddressBus : Model -> Html Msg
viewAddressBus model =
div [ class "addressbus" ]
[ Html.span [ class "label" ] [ text "Addressbus" ]
, Html.span [] [ text (String.fromInt model.pc.addressBus) ]
]
-- END VIEWERS
-- ACTIONS
actRam2DataBus : PC -> PC
actRam2DataBus pc =
let
ab =
pc.addressBus
db =
valueAtInt ab pc.ram
in
{ pc | dataBus = db }
actDataBus2InstructionReg : PC -> PC
actDataBus2InstructionReg pc =
{ pc | instructionReg = pc.dataBus }
actResetUCounter : PC -> PC
actResetUCounter pc =
{ pc | uCounter = 0 }
actInstructionReg2UCounter : PC -> PC
actInstructionReg2UCounter pc =
-- Remove last 5 digits as they are address
-- Multiply by ten, because every instruction is 10 uCodes long
{ pc | uCounter = pc.instructionReg // 100000 * 10 }
actInstructionReg2AddressBus : PC -> PC
actInstructionReg2AddressBus pc =
-- Only bring last 5 digits to AB, because the rest is opcode
{ pc | addressBus = pc.instructionReg - pc.instructionReg // 100000 * 100000 }
actInstructionReg2ProgrammCounter : PC -> PC
actInstructionReg2ProgrammCounter pc =
-- Only bring last 5 digits to AB, because the rest is opcode
{ pc | programmCounter = pc.instructionReg - pc.instructionReg // 100000 * 100000 }
actProgrammCounterIncrement : PC -> PC
actProgrammCounterIncrement pc =
{ pc | programmCounter = pc.programmCounter + 1 }
actProgrammCounter2AddressBus : PC -> PC
actProgrammCounter2AddressBus pc =
{ pc | addressBus = pc.programmCounter }
actDataBus2Accumulator : PC -> PC
actDataBus2Accumulator pc =
{ pc | accumulator = pc.dataBus }
actAccumulator2DataBus : PC -> PC
actAccumulator2DataBus pc =
{ pc | dataBus = pc.accumulator }
actAccumulatorIncrement : PC -> PC
actAccumulatorIncrement pc =
{ pc | accumulator = pc.accumulator + 1 }
actAccumulatorDecrement : PC -> PC
actAccumulatorDecrement pc =
{ pc | accumulator = pc.accumulator - 1 }
actDataBus2Ram : PC -> PC
actDataBus2Ram pc =
let
newRam =
changeAt pc.addressBus pc.dataBus pc.ram
in
{ pc | ram = newRam }
-- END ACTIONS
-- HELPERS
valueAtInt : Int -> List Int -> Int
valueAtInt n l =
case valueAt n l of
Just a ->
a
Nothing ->
0
valueAt : Int -> List a -> Maybe a
valueAt n l =
List.head (List.drop n l)
changeAt : Int -> Int -> List Int -> List Int
changeAt pos newVal list =
let
before =
List.take pos list
after =
List.drop (pos + 1) list
len =
List.length list
in
if pos > len then
let
before2 =
List.append before (List.repeat (pos - len) 0)
in
List.append before2 (newVal :: after)
else
List.append before (newVal :: after)
-- END HELPERS
-- GENERAL
subscriptions : Model -> Sub Msg
subscriptions model =
recieveLocalSession MsgLocalSessionRecieve
init : () -> ( Model, Cmd Msg )
init flags =
( Model initialPC initialUCodes True, Cmd.none )
main : Program () Model Msg
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}