A big ton of refactoring. Basically split up Main.elm into a hand full smaller (more manageable) files.
This commit is contained in:
parent
8d0aded26f
commit
25f793a654
3357
out/js/elm.js
3357
out/js/elm.js
File diff suppressed because it is too large
Load Diff
1274
src/Main.elm
1274
src/Main.elm
File diff suppressed because it is too large
Load Diff
107
src/PC/Defaults.elm
Normal file
107
src/PC/Defaults.elm
Normal 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
96
src/PC/Helpers.elm
Normal 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
112
src/PC/JSON.elm
Normal 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
28
src/PC/PC.elm
Normal 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
78
src/PC/Types.elm
Normal 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
163
src/PC/UActions.elm
Normal 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
246
src/PC/Update.elm
Normal 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
381
src/PC/View.elm
Normal 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.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user