soc.simple package

Submodules

soc.simple.core module

simple core

not in any way intended for production use. connects up FunctionUnits to Register Files in a brain-dead fashion that only permits one and only one Function Unit to be operational.

the principle here is to take the Function Units, analyse their regspecs, and turn their requirements for access to register file read/write ports into groupings by Register File and Register File Port name.

under each grouping - by regfile/port - a list of Function Units that need to connect to that port is created. as these are a contended resource a “Broadcast Bus” per read/write port is then also created, with access to it managed by a PriorityPicker.

the brain-dead part of this module is that even though there is no conflict of access, regfile read/write hazards are not analysed, and consequently it is safer to wait for the Function Unit to complete before allowing a new instruction to proceed.

class soc.simple.core.NonProductionCore(pspec)

Bases: nmigen.hdl.ir.Elaboratable

connect_instruction(m)

uses decoded (from PowerOp) function unit information from CSV files to ascertain which Function Unit should deal with the current instruction.

some (such as OP_ATTN, OP_NOP) are dealt with here, including ignoring it and halting the processor. OP_NOP is a bit annoying because the issuer expects busy flag still to be raised then lowered. (this requires a fake counter to be set).

connect_rdport(m, fu_bitdict, rdpickers, regfile, regname, fspec)
connect_rdports(m, fu_bitdict)

connect read ports

orders the read regspecs into a dict-of-dicts, by regfile, by regport name, then connects all FUs that want that regport by way of a PriorityPicker.

connect_wrport(m, fu_bitdict, wrpickers, regfile, regname, fspec)
connect_wrports(m, fu_bitdict)

connect write ports

orders the write regspecs into a dict-of-dicts, by regfile, by regport name, then connects all FUs that want that regport by way of a PriorityPicker.

note that the write-port wen, write-port data, and go_wr_i all need to be on the exact same clock cycle. as there is a combinatorial loop bug at the moment, these all use sync.

elaborate(platform)
get_byregfiles(readmode)
ports()
soc.simple.core.ortreereduce(tree, attr='data_o')
soc.simple.core.ortreereduce_sig(tree)
soc.simple.core.sort_fuspecs(fuspecs)

soc.simple.issuer module

simple core issuer

not in any way intended for production use. this runs a FSM that:

  • reads the Program Counter from StateRegs
  • reads an instruction from a fixed-size Test Memory
  • issues it to the Simple Core
  • waits for it to complete
  • increments the PC
  • does it all over again

the purpose of this module is to verify the functional correctness of the Function Units in the absolute simplest and clearest possible way, and to at provide something that can be further incrementally improved.

class soc.simple.issuer.TestIssuer(pspec)

Bases: nmigen.hdl.ir.Elaboratable

elaborate(platform)
external_ports()
ports()
class soc.simple.issuer.TestIssuerInternal(pspec)

Bases: nmigen.hdl.ir.Elaboratable

TestIssuer - reads instructions from TestMemory and issues them

efficiency and speed is not the main goal here: functional correctness and code clarity is. optimisations (which almost 100% interfere with easy understanding) come later.

do_dmi(m, dbg)

deals with DMI debug requests

currently only provides read requests for the INT regfile, CR and XER it will later also deal with writing to these regfiles.

elaborate(platform)
execute_fsm(m, core, pc_changed, sv_changed, exec_insn_valid_i, exec_insn_ready_o, exec_pc_valid_o, exec_pc_ready_i)

execute FSM

execute FSM. this interacts with the “issue” FSM through exec_insn_ready/valid (incoming) and exec_pc_ready/valid (outgoing). SVP64 RM prefixes have already been set up by the “issue” phase, so execute is fairly straightforward.

external_ports()
fetch_fsm(m, core, pc, svstate, nia, is_svp64_mode, fetch_pc_ready_o, fetch_pc_valid_i, fetch_insn_valid_o, fetch_insn_ready_i)

fetch FSM

this FSM performs fetch of raw instruction data, partial-decodes it 32-bit at a time to detect SVP64 prefixes, and will optionally read a 2nd 32-bit quantity if that occurs.

fetch_predicate_fsm(m, pred_insn_valid_i, pred_insn_ready_o, pred_mask_valid_o, pred_mask_ready_i)
fetch_predicate_fsm - obtains (constructs in the case of CR)
src/dest predicate masks

https://bugs.libre-soc.org/show_bug.cgi?id=617 the predicates can be read here, by using IntRegs r_ports[‘pred’] or CRRegs r_ports[‘pred’]. in the case of CRs it will have to be done through multiple reads, extracting one relevant at a time. later, a faster way would be to use the 32-bit-wide CR port but this is more complex decoding, here. equivalent code used in ISACaller is “from openpower.decoder.isa.caller import get_predcr”

note: this ENTIRE FSM is not to be called when svp64 is disabled

issue_fsm(m, core, pc_changed, sv_changed, nia, dbg, core_rst, is_svp64_mode, fetch_pc_ready_o, fetch_pc_valid_i, fetch_insn_valid_o, fetch_insn_ready_i, pred_insn_valid_i, pred_insn_ready_o, pred_mask_valid_o, pred_mask_ready_i, exec_insn_valid_i, exec_insn_ready_o, exec_pc_valid_o, exec_pc_ready_i)

issue FSM

decode / issue FSM. this interacts with the “fetch” FSM through fetch_insn_ready/valid (incoming) and fetch_pc_ready/valid (outgoing). also interacts with the “execute” FSM through exec_insn_ready/valid (outgoing) and exec_pc_ready/valid (incoming). SVP64 RM prefixes have already been set up by the “fetch” phase, so execute is fairly straightforward.

ports()
setup_peripherals(m)
tb_dec_fsm(m, spr_dec)

this is a FSM for updating either dec or tb. it runs alternately DEC, TB, DEC, TB. note that SPR pipeline could have written a new value to DEC, however the regfile has “passthrough” on it so this should be ok.

see v3.0B p1097-1099 for Timeer Resource and p1065 and p1076

soc.simple.issuer.get_insn(f_instr_o, pc)
soc.simple.issuer.get_predcr(m, mask, name)

decode SVP64 predicate CR to reg number field and invert status this is identical to _get_predcr in ISACaller

soc.simple.issuer.get_predint(m, mask, name)

decode SVP64 predicate integer mask field to reg number and invert this is identical to the equivalent function in ISACaller except that it doesn’t read the INT directly, it just decodes “what needs to be done” i.e. which INT reg, whether it is shifted and whether it is bit-inverted.

  • all1s is set to indicate that no mask is to be applied.
  • regread indicates the GPR register number to be read
  • invert is set to indicate that the register value is to be inverted
  • unary indicates that the contents of the register is to be shifted 1<<r3
soc.simple.issuer.state_get(m, core_rst, state_i, name, regfile, regnum)

soc.simple.issuer_verilog module

simple core issuer verilog generator

Module contents