A big ton of refactoring. Basically split up Main.elm into a hand full smaller (more manageable) files.

This commit is contained in:
Christian 2021-05-06 14:50:48 +02:00
parent 8d0aded26f
commit 25f793a654
10 changed files with 3140 additions and 2702 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

107
src/PC/Defaults.elm Normal file
View File

@ -0,0 +1,107 @@
module PC.Defaults exposing (..)
import Array exposing (Array)
import PC.Types exposing (..)
import PC.UActions exposing (..)
initalModel : PC_Model
initalModel =
{ pc = initialPC
, uCodes = initialUCodes
}
initialPC : PC
initialPC =
{ ram = initialRam
, dataBus = 0
, addressBus = 0
, instructionReg = 0
, programmCounter = 0
, uCounter = 0
, accumulator = 0
}
initialRam : Array (Int, String)
initialRam = Array.fromList
[ (100005, "LoadA #005") -- 000 -- LoadA #005
, (300000, "IncA") -- 001 -- IncA
, (200005, "StoreA #005") -- 002 -- StoreA #005
, (400000, "JMP #000") -- 003 -- JMP #000
, (0,"") -- 004
, (5,"val") -- 005
, (0, "") -- 006
, (0, "") -- 007
, (0, "") -- 008
, (0, "") -- 009
, (0, "") -- 010
]
initialUCodes : Array UAction
initialUCodes = Array.fromList
[ UA_ProgrammCounter2AddressBus -- 000
, UA_Ram2DataBus -- 001
, UA_DataBus2InstructionReg -- 002
, UA_ProgrammCounterIncrement -- 003
, UA_InstructionReg2UCounter -- 004
, UA_Nothing -- 005
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing -- 009
-- 010 LOADA
, UA_InstructionReg2AddressBus -- 010
, UA_Ram2DataBus -- 011
, UA_DataBus2Accumulator -- 012
, UA_ResetUCounter -- 013
, UA_Nothing -- 014
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing -- 019
-- 020 STOA
, UA_Accumulator2DataBus -- 020
, UA_InstructionReg2AddressBus -- 021
, UA_DataBus2Ram -- 022
, UA_ResetUCounter -- 023
, UA_Nothing --024
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing -- 029
-- 030 INCA
, UA_AccumulatorIncrement -- 030
, UA_ResetUCounter -- 031
, UA_Nothing -- 032
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing -- 039
-- 040 JMP
, UA_InstructionReg2ProgrammCounter -- 040
, UA_ResetUCounter -- 041
, UA_Nothing -- 042
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing
, UA_Nothing -- 049
]

96
src/PC/Helpers.elm Normal file
View File

@ -0,0 +1,96 @@
module PC.Helpers exposing (..)
import Array exposing (Array)
import Http exposing (..)
-- Convert a number from 42 to 0042
-- number : (Prefered positive) whole number
-- length : positive whole number
-- Please note that only 0 are added. The number will not be shortend!
addLeadingZero : Int -> Int -> String
addLeadingZero number length =
let
num_str = String.fromInt number
in
(String.fromList <| List.repeat (length - String.length num_str) '0'
)
++ num_str
-- Get the value at a given position in a List.
-- For performance reasons it might be better
-- to use an Array instead.
valueAt : Int -> List a -> Maybe a
valueAt pos list = List.head <| List.drop pos list
-- Change the value at a given position in a List.
-- If your pos is greater than the length of
-- the list, then the rest is filled with the
-- default element.
overwriteAt : a -> Int -> a ->List a -> List a
overwriteAt default pos newVal list =
let
len = List.length list
in
if pos == 0 then
newVal :: list
else if pos > len then
list ++
(List.repeat (pos-len) default) ++
[newVal]
else
let
before = List.take pos list
after = List.drop (pos+1) list
in
before ++ [newVal] ++ after
overwriteAt_Arr : a -> Int -> a -> Array a -> Array a
overwriteAt_Arr default pos newVal list =
let
len = Array.length list
in
if pos == 0 then
Array.append (Array.fromList [newVal]) list
else if pos > len then
Array.append list
<| Array.append (Array.repeat (pos-len) default)
<| Array.fromList [newVal]
else
Array.set pos newVal list
-- Prints Http Errors into something readable
printHttpError : Http.Error -> String
printHttpError err =
case err of
Http.BadUrl str -> "Bad Url: " ++ str
Http.Timeout -> "Timeout"
Http.NetworkError -> "Network Error"
Http.BadStatus num -> "Bad Status: " ++ String.fromInt num
Http.BadBody str -> "Bad Body: " ++ str
seperateInstructionsEntry : Int -> (Int, Int)
seperateInstructionsEntry i =
let
instruction = i // 100000
address = i - instruction*100000
in
(instruction, address)
valueAtRam : Int -> Array (Int, String) -> (Int, String)
valueAtRam pos arr =
case Array.get pos arr of
Just a -> a
Nothing -> (0, "")
changeAtRam : Int -> Int -> Array (Int, String) -> Array (Int,String)
changeAtRam pos newVal list =
let
(_,comment) = valueAtRam pos list
in
overwriteAt_Arr (0, "") pos (newVal, comment) list

112
src/PC/JSON.elm Normal file
View File

@ -0,0 +1,112 @@
module PC.Json exposing ( pcModelDecoder
, pcModelEncoder
, tuple2Decoder
, tuple2Encoder
)
import PC.Types exposing (..)
import Maybe
import Array exposing (Array)
import Json.Encode as JE exposing (Value)
import Json.Decode as JD exposing (Decoder)
import PC.Types exposing (..)
import PC.UActions exposing (..)
-- ##########################################################
-- Decoders
-- ##########################################################
pcModelDecoder : Decoder PC_Model
pcModelDecoder =
JD.map2
PC_Model
(JD.field "pc" pcDecoder)
(JD.field "uCodes" uCodeDecoder)
pcDecoder : Decoder PC
pcDecoder =
JD.map7
PC
(JD.field "ram" <| JD.array <| tuple2Decoder JD.int JD.string)
(JD.field "dataBus" JD.int)
(JD.field "addressBus" JD.int)
(JD.field "instructionReg" JD.int)
(JD.field "programmCounter" JD.int)
(JD.field "uCounter" JD.int)
(JD.field "accumulator" JD.int)
uCodeDecoder : Decoder (Array UAction)
uCodeDecoder =
JD.array <| JD.map uActionDecoder JD.string
uActionDecoder : String -> UAction
uActionDecoder str =
Maybe.withDefault UA_Nothing <| string2uAction str
tuple2Decoder : Decoder a -> Decoder b -> Decoder (a,b)
tuple2Decoder enc1 enc2 =
JD.map2 Tuple.pair
(JD.index 0 enc1)
(JD.index 1 enc2)
-- ##########################################################
-- ##########################################################
-- ##########################################################
-- Encoders
-- ##########################################################
pcModelEncoder : PC_Model -> Value
pcModelEncoder model =
JE.object
[ ( "pc" , pcEncoder model.pc )
, ( "uCodes" , uCodesEncoder model.uCodes )
]
pcEncoder : PC -> Value
pcEncoder pc =
JE.object
[ ( "addressBus" , JE.int pc.addressBus )
, ( "dataBus" , JE.int pc.dataBus )
, ( "instructionReg" , JE.int pc.instructionReg )
, ( "programmCounter" , JE.int pc.programmCounter )
, ( "uCounter" , JE.int pc.uCounter )
, ( "accumulator" , JE.int pc.accumulator )
, ( "ram" , ramEncoder pc.ram )
]
ramEncoder : Array (Int, String) -> Value
ramEncoder arr =
JE.array
(tuple2Encoder JE.int JE.string)
arr
uCodesEncoder : Array UAction -> Value
uCodesEncoder uActions =
JE.array encodeSingleuCode uActions
encodeSingleuCode : UAction -> Value
encodeSingleuCode action =
let
uCode = uAction2UCode action
in
JE.string uCode.id
tuple2Encoder : (a -> Value) -> (b -> Value) -> (a,b) -> Value
tuple2Encoder encA encB (valA, valB) =
JE.list identity [ encA valA, encB valB ]
-- ##########################################################
-- ##########################################################
-- Done.

28
src/PC/PC.elm Normal file
View File

@ -0,0 +1,28 @@
module PC.PC exposing (..)
import Html exposing (Html)
--import Json.Encode as JE
import Json.Decode as JD
import PC.Types exposing (..)
import PC.Defaults exposing (..)
import PC.Helpers exposing (..)
import PC.Update exposing (..)
import PC.View exposing (..)
update : PC_Msg -> PC_Model -> (PC_Model, PC_AfterUpdateAction)
update = pc_update
view : PC_Model -> Html PC_Msg
view = pc_view
init : PC_Model
init = initalModel

78
src/PC/Types.elm Normal file
View File

@ -0,0 +1,78 @@
module PC.Types exposing (..)
import Array exposing (Array)
pcModelVersion = "3"
type alias PC_Model =
{ pc : PC
, uCodes : Array UAction
}
type alias PC =
{ ram : Array (Int, String)
, dataBus : Int
, addressBus : Int
, instructionReg : Int
, programmCounter : Int
, uCounter : Int
, accumulator : Int
}
type alias UCode =
{ variant : UAction
, id : String
, action : PC -> PC
, label : String
}
type UAction
= UA_Accumulator2DataBus
| UA_AccumulatorDecrement
| UA_AccumulatorIncrement
| UA_DataBus2Accumulator
| UA_DataBus2InstructionReg
| UA_DataBus2Ram
| UA_InstructionReg2AddressBus
| UA_InstructionReg2ProgrammCounter
| UA_InstructionReg2UCounter
| UA_ProgrammCounterIncrement
| UA_InstructionReg2ProgrammCounterIfAccEq0
| UA_Ram2DataBus
| UA_ResetUCounter
| UA_ProgrammCounter2AddressBus
| UA_Nothing
-- To make it easier to understand everything has name convention
-- PM_ -> PC_Msg in general
-- PM_B_ -> for a Button
-- PM_C_ -> for a Checkbox
-- PM_F_ -> for a TextField
type PC_Msg
= PM_B_UCycleStep
| PM_B_InstructionStep
| PM_B_Reset
| PM_B_RamAddBelow
| PM_B_CuAddBelow
| PM_F_RamEditInstr Int String
| PM_F_RamEditAddress Int String
| PM_F_RamEditComment Int String
| PM_F_CuEditAction Int String
| PM_F_CuInstrRegEditAddr String
| PM_F_CuInstrRegEditInstr String
| PM_F_CuProgCounterEdit String
| PM_F_CuUCounterEdit String
| PM_F_EditAddressBus String
| PM_F_EditDataBus String
| PM_F_AluEdit String
| PM_ManualStep UAction
-- Tells main what is supposed
-- to happen after a update
type PC_AfterUpdateAction
= PUA_Nothing -- Do nothing
| PUA_Storage -- Update localStorage
| PUA_Scroller -- Scroll to value
| PUA_Storage_And_Scroller -- Update localStorage and scroll to values

163
src/PC/UActions.elm Normal file
View File

@ -0,0 +1,163 @@
module PC.UActions exposing ( uCodes
, uAction2Label
, string2uAction
, uAction2UCode )
import Array exposing (Array)
import Tuple
import PC.Types exposing (..)
import PC.Helpers exposing (..)
uCodes : List UCode
uCodes =
[ UCode UA_Accumulator2DataBus "acc2db" actAccumulator2DataBus "Acc -> DataBus"
, UCode UA_AccumulatorDecrement "accDec" actAccumulatorDecrement "Acc --"
, UCode UA_AccumulatorIncrement "accInc" actAccumulatorIncrement "Acc ++"
, UCode UA_DataBus2Accumulator "db2acc" actDataBus2Accumulator "DataBus -> Acc"
, UCode UA_DataBus2InstructionReg "db2ir" actDataBus2InstructionReg "DataBus -> InstReg"
, UCode UA_DataBus2Ram "db2ram" actDataBus2Ram "DataBus -> Ram"
, UCode UA_InstructionReg2AddressBus "ir2ab" actInstructionReg2AddressBus "InstReg -> AddrBus"
, UCode UA_InstructionReg2ProgrammCounter "ir2pc" actInstructionReg2ProgrammCounter "InstReg -> ProgCount"
, UCode UA_InstructionReg2UCounter "ir2uc" actInstructionReg2UCounter "InstReg -> µCounter"
, UCode UA_ProgrammCounterIncrement "pcInc" actProgrammCounterIncrement "ProgCounter ++"
, UCode UA_Ram2DataBus "ram2db" actRam2DataBus "Ram -> DataBus"
, UCode UA_ResetUCounter "ucReset" actResetUCounter "µCounter = 0"
, UCode UA_ProgrammCounter2AddressBus "pc2ab" actProgrammCounter2AddressBus "ProgCounter -> AddrBus"
, UCode UA_Nothing "n" (\s -> s) "Empty"
, UCode UA_InstructionReg2ProgrammCounterIfAccEq0
"ir2pciacceq0" actInstructionReg2ProgrammCounterIfAccEq0 "Acc == 0 => InstReg -> ProgCounter"
]
-- #######################################################################################
-- ACTIONS
-- #######################################################################################
actRam2DataBus : PC -> PC
actRam2DataBus pc =
let
ab =
pc.addressBus
db =
Tuple.first <| valueAtRam 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 =
-- Multiply by ten, because every instruction is 10 uCodes long
let
(instruction, address) = seperateInstructionsEntry pc.instructionReg
in
{ pc | uCounter = instruction * 10}
actInstructionReg2AddressBus : PC -> PC
actInstructionReg2AddressBus pc =
let
(instruction, address) = seperateInstructionsEntry pc.instructionReg
in
{ pc | addressBus = address }
actInstructionReg2ProgrammCounter : PC -> PC
actInstructionReg2ProgrammCounter pc =
let
(instruction, address) = seperateInstructionsEntry pc.instructionReg
in
{ pc | programmCounter = address }
actProgrammCounterIncrement : PC -> PC
actProgrammCounterIncrement pc =
{ pc | programmCounter = pc.programmCounter + 1 }
actProgrammCounter2AddressBus : PC -> PC
actProgrammCounter2AddressBus pc =
{ pc | addressBus = pc.programmCounter }
actInstructionReg2ProgrammCounterIfAccEq0 : PC -> PC
actInstructionReg2ProgrammCounterIfAccEq0 pc =
if pc.accumulator == 0 then
let
(_,addr) = seperateInstructionsEntry pc.instructionReg
in
{ pc | programmCounter = addr }
else
pc
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 =
changeAtRam pc.addressBus pc.dataBus pc.ram
in
{ pc | ram = newRam }
-- #################################################################
-- Helpers
-- #################################################################
uAction2Label : UAction -> String
uAction2Label variant =
let
filtered_list = List.filter (\u -> u.variant == variant ) uCodes
in
case List.head filtered_list of
Just uCode -> uCode.label
Nothing -> "IDK"
uAction2UCode : UAction -> UCode
uAction2UCode variant =
let
filtered_list = List.filter (\u -> u.variant == variant ) uCodes
in
case List.head filtered_list of
Just uCode -> uCode
Nothing -> UCode UA_Nothing "n" (\s -> s) "Empty"
string2uAction : String -> Maybe UAction
string2uAction str =
let
filtered_list = List.filter (\u -> u.id == str) uCodes
in
case List.head filtered_list of
Just uCode -> Just uCode.variant
_ -> Nothing

246
src/PC/Update.elm Normal file
View File

@ -0,0 +1,246 @@
module PC.Update exposing (pc_update)
import Array exposing (Array)
import PC.Types exposing (..)
import PC.UActions exposing (..)
import PC.Defaults exposing (..)
import PC.Helpers exposing (..)
pc_update : PC_Msg -> PC_Model -> (PC_Model, PC_AfterUpdateAction)
pc_update msg model =
case msg of
PM_B_UCycleStep ->
( uStepPC model
, if model.pc.uCounter == 0 then PUA_Storage_And_Scroller
else PUA_Scroller
)
PM_B_InstructionStep ->
( executeInstruction model
, PUA_Storage_And_Scroller )
PM_B_Reset ->
( { model | pc = { initialPC | ram = model.pc.ram } }
, PUA_Storage_And_Scroller )
PM_B_RamAddBelow ->
let
old_pc = model.pc
new_pc = {old_pc | ram = Array.append old_pc.ram <| Array.fromList [(0, "")]}
in
({model | pc = new_pc}
, PUA_Storage)
PM_B_CuAddBelow ->
({model | uCodes = Array.append model.uCodes <| Array.repeat 10 UA_Nothing}
, PUA_Storage)
PM_F_RamEditAddress addr may_int ->
case String.toInt may_int of
Just int ->
let
(inst,_) = seperateInstructionsEntry ( Tuple.first <| valueAtRam addr model.pc.ram )
new_val = inst * 100000 + int
old_pc = model.pc
new_pc = { old_pc | ram = (changeAtRam addr new_val old_pc.ram) }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> (model, PUA_Nothing)
PM_F_RamEditInstr addr may_int ->
case String.toInt may_int of
Just int ->
let
(_,address) = seperateInstructionsEntry ( Tuple.first <| valueAtRam addr model.pc.ram )
new_val = int * 100000 + address
old_pc = model.pc
new_pc = { old_pc | ram = (changeAtRam addr new_val old_pc.ram) }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_F_RamEditComment addr str ->
let
(val, _) = valueAtRam addr model.pc.ram
old_pc = model.pc
new_pc = { old_pc | ram = overwriteAt_Arr (0,"") addr (val, str) old_pc.ram }
in
({ model | pc = new_pc }, PUA_Storage)
PM_F_CuEditAction addr may_action ->
case string2uAction may_action of
Just action ->
let
newCode = Array.set addr action model.uCodes
in
({ model | uCodes = newCode }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_F_CuInstrRegEditAddr text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
(instr,_) = seperateInstructionsEntry old_pc.instructionReg
new_pc = { old_pc | instructionReg = instr * 100000 + int }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_F_CuInstrRegEditInstr text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
(_,addr) = seperateInstructionsEntry old_pc.instructionReg
new_pc = { old_pc | instructionReg = int * 100000 + addr }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_F_CuProgCounterEdit text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
new_pc = { old_pc | programmCounter = int }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_F_CuUCounterEdit text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
new_pc = { old_pc | uCounter = int }
in
( { model | pc = new_pc }, PUA_Storage_And_Scroller )
_ -> ( model, PUA_Nothing )
PM_F_EditAddressBus text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
new_pc = { old_pc | addressBus = int }
in
( { model | pc = new_pc }, PUA_Storage_And_Scroller )
_ -> ( model, PUA_Nothing )
PM_F_EditDataBus text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
new_pc = { old_pc | dataBus = int }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_F_AluEdit text ->
case String.toInt text of
Just int ->
let old_pc = model.pc
new_pc = { old_pc | accumulator = int }
in
({ model | pc = new_pc }, PUA_Storage)
_ -> ( model, PUA_Nothing )
PM_ManualStep action ->
let
instruction = getAction action
new_model = { model | pc = instruction model.pc }
in
( new_model, PUA_Storage_And_Scroller )
-- ###############################################################################
-- ###############################################################################
-- ###############################################################################
-- Update Helpers
-- ###############################################################################
-- Practically a part of uStepPC but sepeated for manual mode
getAction : UAction -> (PC -> PC)
getAction uAction =
let
possible_instructions =
List.filter (\u -> u.variant == uAction) uCodes
in
case List.head possible_instructions of
Just uCode ->
uCode.action
_ ->
(\s -> s)
uStepPC : PC_Model -> PC_Model
uStepPC model =
let
uCounter =
model.pc.uCounter
may_code : Maybe UAction
may_code = Array.get uCounter model.uCodes
--valueAt uCounter model.uCodes
in
case may_code of
Just code ->
let
-- code :: UAction
old_pc = model.pc
temp_pc = { old_pc | uCounter = uCounter + 1 }
uCode = uAction2UCode code
f = uCode.action
new_pc = f temp_pc
in
{ model | pc = new_pc }
--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
executeInstruction : PC_Model -> PC_Model
executeInstruction model =
let
new_model = uStepPC model
in
if new_model.pc.uCounter == 0 then
uStepPC new_model
else
executeInstruction new_model
-- ###############################################################################
-- ###############################################################################
-- Done.

381
src/PC/View.elm Normal file
View File

@ -0,0 +1,381 @@
module PC.View exposing (pc_view)
import Html exposing (Html, button, div, h1, p, text)
import Html.Attributes as HAttr exposing (class, classList, value)
import Html.Events as HEvent exposing (onClick, onInput)
import Html.Lazy exposing (lazy)
import Array exposing (Array)
import Json.Decode as JD
import PC.Types exposing (..)
import PC.UActions exposing (..)
import PC.Helpers exposing (..)
pc_view : PC_Model -> Html PC_Msg
pc_view model = div []
[ div
[ class "grid-fullwidth", class "grid-addressbus" ]
[ lazy viewAddressBus model ]
, lazy viewRam model
, lazy viewCu model
, lazy viewAlu model
, div
[ class "grid-fullwidth", class "grid-databus" ]
[ lazy viewDataBus model ]
]
-- #####################################################################
-- #####################################################################
-- #####################################################################
-- RAM
-- #####################################################################
viewRam : PC_Model -> Html PC_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" ]
, Html.th [] [ text "Comment" ]
]
]
, lazy viewRamContent model
]
]
, drawArrow Bottom Down UA_Ram2DataBus "Ram -> DataBus"
, drawArrow Bottom Up UA_DataBus2Ram "DataBus -> Ram"
]
viewRamContent : PC_Model -> Html PC_Msg
viewRamContent model =
let
--indexedRam =
-- List.indexedMap Tuple.pair <| Array.toList model.pc.ram
ram2table : Int -> (Int, String) -> Html PC_Msg
ram2table id entry =
let
(val,comment) = entry
(instruction, address) = seperateInstructionsEntry val
in
Html.tr
[ classList [ ( "current", id == model.pc.addressBus ) ] ]
[ Html.td [ class "num" ] [ text (addLeadingZero id 3) ]
, Html.td [ class "num " ]
[ Html.input
[ HAttr.type_ "number"
, HAttr.value <| addLeadingZero instruction 3
, onInput <| PM_F_RamEditInstr id
, class "ram-entry"
, class "instruction"
]
[]
, Html.input
[ HAttr.type_ "number"
, HAttr.value <| addLeadingZero address 5
, onInput <| PM_F_RamEditAddress id
, class "ram-entry"
, class "address"
]
[]
]
, Html.td[ class "comment" ]
[ Html.input
[ HAttr.type_ "text"
, HAttr.value comment
, onInput <| PM_F_RamEditComment id ]
[]
]
]
in
Html.tbody []
((Array.toList <| Array.indexedMap ram2table model.pc.ram)
++
[ Html.tr []
[ Html.td [] []
, Html.td []
[ button
[ onClick PM_B_RamAddBelow ]
[ text "Add Entry"]
]
, Html.td [][]
]
]
)
-- #####################################################################
-- #####################################################################
-- #####################################################################
-- Control Unit
-- #####################################################################
viewCu : PC_Model -> Html PC_Msg
viewCu model =
let
( instrRegInst, instrRegAddr ) = seperateInstructionsEntry model.pc.instructionReg
in
div [ class "section", class "cu" ]
[ drawArrow Top Up UA_InstructionReg2AddressBus "InstR -> AddrB"
, drawArrow Top Up UA_ProgrammCounter2AddressBus "ProgCounter -> AddrB"
--, div [ class "arrow", class "up", class "top"]
-- [ div [ class "button" ]
-- [ Html.a [ onClick (PM_ManualStep ActInstructionReg2AddressBus)] [ text "InstR -> AddrB" ]]
-- , div [] []
-- ]
--, div [ class "arrow", class "up", class "top", class "arrow2"]
-- [ div [ class "button" ]
-- [ Html.a [ onClick (PM_ManualStep ActProgrammCounter2AddressBus)] [ text "ProgCounter -> AddrB" ]]
-- , div [] []
-- ]
, h1 [ class "header" ] [ text "Control Unit" ]
, p []
[ div [class "input-row"]
[ Html.label [ HAttr.for "cu-progcounter" ] [ text "Programm Counter:" ]
, button
[ onClick <| PM_ManualStep UA_InstructionReg2ProgrammCounter ]
[ text "InstRA -> " ]
, Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-progcounter"
, value (addLeadingZero model.pc.programmCounter 3)
, onInput PM_F_CuProgCounterEdit
] []
]
, div [class "input-row"]
[ Html.label [ HAttr.for "cu-instrReg" ] [ text "Instruction Register:" ]
, div []
[ Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-instrReg"
, class "instruction"
, value (addLeadingZero instrRegInst 3)
, onInput PM_F_CuInstrRegEditInstr
] []
, Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-instrReg"
, class "address"
, value (addLeadingZero instrRegAddr 5)
, onInput PM_F_CuInstrRegEditAddr
] []
]
]
, div [class "input-row"]
[ Html.label [ HAttr.for "cu-uCounter" ] [ text "µCode Counter:" ]
, button
[ onClick <| PM_ManualStep UA_InstructionReg2UCounter
]
[ text "IntrRI ->" ]
, Html.input
[ HAttr.type_ "number"
, HAttr.id "cu-uCounter"
, value (addLeadingZero model.pc.uCounter 4)
, onInput PM_F_CuUCounterEdit
] []
]
]
, div [ class "scroller" ]
[ viewCuUCode model
]
--, div [ class "arrow", class "up"]
-- [ div [ class "button" ]
-- [ Html.a [ onClick (MsgManualStep ActDataBus2InstructionReg) ] [ text "DB -> InstR" ]]
-- , div [] []
-- ]
, drawArrow Bottom Up UA_DataBus2InstructionReg "DB -> InstR"
]
viewCuUCode : PC_Model -> Html PC_Msg
viewCuUCode model =
Html.table []
[ Html.thead [ class "head" ]
[ Html.tr []
[ Html.th [ class "address" ] [ text "µCounter" ]
, Html.th [] [ text "µCode" ]
]
]
, lazy viewCuUCodeContent model
]
viewCuUCodeContent : PC_Model -> Html PC_Msg
viewCuUCodeContent model =
let
list2table : Int -> UAction -> Html PC_Msg
list2table id code =
Html.tr
[ classList [ ( "current", id == model.pc.uCounter ), ("empty", code == UA_Nothing) ] ]
[ Html.td [ class "num" ] [ text (addLeadingZero id 4) ]
, Html.td [] [ viewCuInstrSelect id code ]
]
in
Html.tbody []
((Array.toList <| Array.indexedMap list2table model.uCodes)
++
[ Html.tr []
[ Html.td [] []
, Html.td []
[ button
[ onClick PM_B_CuAddBelow ]
[ text "Add Entry"]
]
]
]
)
viewCuInstrSelect : Int -> UAction -> Html PC_Msg
viewCuInstrSelect id current =
let
info2option uCode =
Html.option
[ HAttr.selected (uCode.variant == current)
, HAttr.value uCode.id ]
[ text uCode.label ]
listOptions = List.map info2option uCodes
in
Html.select
[ HEvent.on "change" ( JD.map (PM_F_CuEditAction id) selectCuValueDecoder) ]
listOptions
viewInstrEntry : Int -> Html PC_Msg
viewInstrEntry i =
let
(instruction, address) = seperateInstructionsEntry i
in
text ( (addLeadingZero instruction 3) ++ " " ++ (addLeadingZero address 5) )
-- #####################################################################
-- #####################################################################
-- #####################################################################
-- ALU
-- #####################################################################
viewAlu : PC_Model -> Html PC_Msg
viewAlu model =
div [ class "section", class "alu" ]
[ h1 [ class "header" ] [ text "ALU" ]
, p []
[ Html.label [ HAttr.for "alu-accumulator" ] [ text "Accumulator:" ]
, Html.input
[ HAttr.type_ "number"
, HAttr.id "alu-accumulator"
, value (addLeadingZero model.pc.accumulator 8)
, onInput PM_F_AluEdit
] []
]
, p []
[ button [ onClick <| PM_ManualStep UA_AccumulatorIncrement ] [ text "Acc ++" ]
, button [ onClick <| PM_ManualStep UA_AccumulatorDecrement ] [ text "Acc --" ]
]
, drawArrow Bottom Up UA_DataBus2Accumulator "DB -> ALU"
, drawArrow Bottom Down UA_Accumulator2DataBus "ALU -> DB"
--, 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 [] []
-- ]
]
-- #####################################################################
-- Busses
-- #####################################################################
viewDataBus : PC_Model -> Html PC_Msg
viewDataBus model =
div [ class "databus" ]
[ Html.span [ class "label" ] [ text "Databus" ]
, Html.span []
[ Html.input
[ HAttr.type_ "number"
, value (addLeadingZero model.pc.dataBus 8)
, onInput PM_F_EditDataBus
] []
]
]
viewAddressBus : PC_Model -> Html PC_Msg
viewAddressBus model =
div [ class "addressbus" ]
[ Html.span [ class "label" ] [ text "Addressbus" ]
, Html.span []
[ Html.input
[ HAttr.type_ "number"
, value (addLeadingZero model.pc.addressBus 3)
, onInput PM_F_EditAddressBus
] []
]
]
-- #####################################################################
-- #####################################################################
-- #####################################################################
-- Helpers
-- #####################################################################
type Arrow_Pos = Top | Bottom
type Arrow_Dir = Up | Down
drawArrow : Arrow_Pos -> Arrow_Dir -> UAction -> String -> Html PC_Msg
drawArrow pos dir act str =
div
[ HAttr.classList
[ ("arrow", True)
, ("top", pos == Top)
, ("up", dir == Up)
, ("down", dir == Down)]
]
[ div [ class "button" ]
[ Html.a
[ onClick (PM_ManualStep act) ]
[ text str ]
]
, div [] []
]
selectCuValueDecoder : JD.Decoder String
selectCuValueDecoder =
JD.field "target" ( JD.field "value" JD.string)
-- #####################################################################
-- #####################################################################
-- Done.