Thread: [myhdl-list] Python Hardware Processor
Brought to you by:
jandecaluwe
From: Norbo <Nor...@gm...> - 2012-02-04 13:49:12
|
To show where i am at: ##################################### # File: Core.py # Author: Norbert Feurle # Date: 4.2.2012 # # Description: Python Hardware Processor # This Code implements a Hardware CPU in myhdl. The code for the cpu is directly written in python # and since the hardware description is also in python, the programmcode is automatically into the design # The cool thing is that by this approach only memory and stack hardware is allocated in Hardware which is # really needed. Simulation of the code on the cpu running is no problem. (only python needed!) # The bytecode of python is executed at the cpu at one instruction per cycle # By now only simple bytecode instructions are supported # You can simply instantiate more Hardware CPUs on an FPGA with different program code to make it run parallel # # License: Pro life licence. # You are not allowed to this code for any purpose which is in any kind disrespectfully to life and/or freedom # In such a case it remains my property # for example: You are not allowed to build weapons, or large-scale animal husbandry automation equipment or anything # that is used to harm, destroy or is used to frighten living beings at an unacceptable rate, or build hardware # with it where te workers dont get paid appropriate, or any process where the waste issue isnt solved in a sustainable way, # etc.. # # If you use it respectfully you are allowed to use it for free and are welcome to contribute with your changes/extensions ################################################################################################# ######################################################################################## #### Limitations: #### no lists, no dicts no tuples, no float, no complex numbers, #### no classmembers,no function calls, no multiplication, no exeptions, no for x in xxx:, etc. ######################################################################################## ### What is supported: ### ints(with x bits), no other python types ### simple if and while and assignments ### Operators: +, ^ , |, &. - (minus doesent work yet becaus i never used signed (big TODO)) ### Simple Digital IO with PORTs ### And of corse some bugs ######################################################################################## ##### The main programm for the python hardware porcessor to execute #### def CPU_main(): ## Reserves for IO Module ### global PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT PORTA_IN=0 #needs to bee here to reserve the right addresses (0 is written to nowhere) PORTB_IN=0 PORTC_OUT=0 PORTD_OUT=0 ################# x=0 while 1: x=x+1 if PORTA_IN==1: PORTC_OUT= PORTC_OUT^1 if x<20: PORTD_OUT=x elif x>=20 and x<25: PORTD_OUT=2**30+x else: PORTD_OUT=x ##### End of the main programm #### from myhdl import * import math import dis HAVE_ARGUMENT=dis.HAVE_ARGUMENT GLOBAL_PROGRAM=tuple([ord(i) for i in CPU_main.func_code.co_code]) + (0,0,) #because arguments are also read GLOBAL_CONSTANTS=(0,)+CPU_main.func_code.co_consts[1:] # because constant None is on address 0 but cpu only supports int GLOBAL_STACK_SIZE=CPU_main.func_code.co_stacksize GLOBAL_NUMBERSTACK_OPS=19 STACK_NOP,STACK_ADD,STACK_POSITIVE,STACK_NOT,STACK_NEGATIVE,STACK_INVERT,STACK_RSHIFT,STACK_LSHIFT,STACK_AND,STACK_SUB,STACK_OR,STACK_XOR,STACK_POP,STACK_LOAD,STACK_CMP,STACK_ROT_FOUR, STACK_ROT_TWO, STACK_ROT_THREE,STACK_DUP_TOP=range(GLOBAL_NUMBERSTACK_OPS) def RAM(dout, din, addr, we, clk, WORD_SZ=8, DEPTH=16384): """ """ mem = [Signal(intbv(0)[WORD_SZ:]) for i in range(DEPTH)] @always(clk.posedge) def write(): if we: mem[int(addr)].next = din @always_comb def read(): dout.next = mem[int(addr)] return write,read def ROM(dout,addr,CONTENT): @always_comb def rom_logic(): dout.next= CONTENT[int(addr)] return rom_logic def ProgrammROM(Opcode,Arg1,Arg2,addr,CONTENT): @always_comb def progrom_logic(): Opcode.next= CONTENT[int(addr)] Arg1.next= CONTENT[int(addr+1)] Arg2.next= CONTENT[int(addr+2)] return progrom_logic def Stack(clk,rst,TopData_Out,Data_In,StackOP,CMPmode,WORD_SZ=32,SIZE=GLOBAL_STACK_SIZE): Stack_mem = [Signal(intbv(0)[WORD_SZ:]) for i in range(SIZE)] Next_TSO_Data=Signal(intbv(0)[WORD_SZ:]) TOS_Data=Signal(intbv(0)[WORD_SZ:]) TOS1_Data=Signal(intbv(0)[WORD_SZ:]) TOS2_Data=Signal(intbv(0)[WORD_SZ:]) TOS_Data_RD=Signal(intbv(0)[WORD_SZ:]) TOS1_Data_RD=Signal(intbv(0)[WORD_SZ:]) TOS2_Data_RD=Signal(intbv(0)[WORD_SZ:]) TOS_pointer_next=Signal(intbv(0,min=0,max=SIZE)) TOS_pointer= Signal(intbv(0,min=0,max=SIZE)) TOS1_pointer= Signal(intbv(0,min=0,max=SIZE)) TOS2_pointer= Signal(intbv(0,min=0,max=SIZE)) #TOS3_pointer= Signal(intbv(0,min=0,max=SIZE)) enable_stackpointer_increase=Signal(bool(0)) enable_stackpointer_deacrease=Signal(bool(0)) @always(clk.posedge,rst.negedge) def seq_logic(): if rst == 0: TOS_pointer_next.next=0 TOS_pointer.next=0 TOS1_pointer.next=0 TOS2_pointer.next=0 #TOS3_pointer.next=0 for indexer in range(SIZE): Stack_mem[int(indexer)].next=0 else: if enable_stackpointer_increase: TOS_pointer_next.next=(TOS_pointer_next+1)% SIZE TOS_pointer.next=TOS_pointer_next TOS1_pointer.next=TOS_pointer TOS2_pointer.next=TOS1_pointer if enable_stackpointer_deacrease: if TOS2_pointer==0: TOS2_pointer.next=SIZE-1 else: TOS2_pointer.next=TOS2_pointer-1 TOS1_pointer.next=TOS2_pointer TOS_pointer.next=TOS1_pointer TOS_pointer_next.next=TOS_pointer #Stackpointer.next=Stackpointer_next #attention if stacksize is to smalll the lower one gets overwritten #so the ordering is important # TODO: stacksize==1 would not work Stack_mem[int(TOS2_pointer)].next=TOS2_Data Stack_mem[int(TOS1_pointer)].next=TOS1_Data Stack_mem[int(TOS_pointer)].next=TOS_Data Stack_mem[int(TOS_pointer_next)].next=Next_TSO_Data @always_comb def comb_logic(): Next_TSO_Data.next=Stack_mem[int(TOS_pointer_next)] TOS_Data.next=Stack_mem[int(TOS_pointer)] TOS1_Data.next=Stack_mem[int(TOS1_pointer)] TOS2_Data.next=Stack_mem[int(TOS2_pointer)] enable_stackpointer_increase.next=1 enable_stackpointer_deacrease.next=0 if StackOP==STACK_NOP: enable_stackpointer_increase.next=0 elif StackOP==STACK_ADD: Next_TSO_Data.next=TOS1_Data_RD+TOS_Data_RD elif StackOP==STACK_POSITIVE: #??? Next_TSO_Data.next=TOS_Data_RD elif StackOP==STACK_NOT: Next_TSO_Data.next=TOS_Data_RD elif StackOP==STACK_NEGATIVE: Next_TSO_Data.next=-TOS_Data_RD elif StackOP==STACK_INVERT: Next_TSO_Data.next=~TOS_Data_RD elif StackOP==STACK_RSHIFT: Next_TSO_Data.next=TOS1_Data_RD>>TOS_Data_RD elif StackOP==STACK_LSHIFT: Next_TSO_Data.next=TOS1_Data_RD<<TOS_Data_RD elif StackOP==STACK_AND: Next_TSO_Data.next=TOS1_Data_RD&TOS_Data_RD elif StackOP==STACK_SUB: Next_TSO_Data.next=TOS1_Data_RD-TOS_Data_RD elif StackOP==STACK_OR: Next_TSO_Data.next=TOS1_Data_RD|TOS_Data_RD elif StackOP==STACK_XOR: Next_TSO_Data.next=TOS1_Data_RD^TOS_Data_RD elif StackOP==STACK_POP: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 elif StackOP==STACK_LOAD: Next_TSO_Data.next=Data_In elif StackOP==STACK_ROT_TWO: enable_stackpointer_increase.next=0 TOS_Data.next=TOS1_Data_RD TOS1_Data.next=TOS_Data_RD elif StackOP==STACK_ROT_THREE: enable_stackpointer_increase.next=0 TOS_Data.next=TOS1_Data_RD TOS1_Data.next=TOS2_Data_RD TOS2_Data.next=TOS_Data_RD #elif StackOP==STACK_ROT_FOUR: ##TODO #TOS_Data.next=Stack_mem[int(TOS_pointer)] # TOS1_Data.next=Stack_mem[int(TOS1_pointer)] # TOS2_Data.next=Stack_mem[int(TOS2_pointer)] elif StackOP==STACK_DUP_TOP: Next_TSO_Data.next=TOS_Data_RD elif StackOP==STACK_CMP: if CMPmode==0: #operator < if TOS1_Data_RD<TOS_Data_RD: Next_TSO_Data.next=1 else: Next_TSO_Data.next=0 if CMPmode==1: #operator <= if TOS1_Data_RD<=TOS_Data_RD: Next_TSO_Data.next=1 else: Next_TSO_Data.next=0 if CMPmode==2: #operator == if TOS1_Data_RD==TOS_Data_RD: Next_TSO_Data.next=1 else: Next_TSO_Data.next=0 if CMPmode==3: #operator != if TOS1_Data_RD!=TOS_Data_RD: Next_TSO_Data.next=1 else: Next_TSO_Data.next=0 if CMPmode==4: #operator > if TOS1_Data_RD>TOS_Data_RD: Next_TSO_Data.next=1 else: Next_TSO_Data.next=0 if CMPmode==5: #operator >= if TOS1_Data_RD>=TOS_Data_RD: Next_TSO_Data.next=1 else: Next_TSO_Data.next=0 else: enable_stackpointer_increase.next=0 @always_comb def comb_logic2(): TOS_Data_RD.next=Stack_mem[int(TOS_pointer)] TOS1_Data_RD.next=Stack_mem[int(TOS1_pointer)] TOS2_Data_RD.next=Stack_mem[int(TOS2_pointer)] TopData_Out.next=Stack_mem[int(TOS_pointer)] return seq_logic,comb_logic,comb_logic2 def IOModule(clk,rst,dout,din,addr,we,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,WIDTH=32): Sync_in1_PORTA=Signal(intbv(0)[WIDTH:]) Sync_in2_PORTA=Signal(intbv(0)[WIDTH:]) Sync_in1_PORTB=Signal(intbv(0)[WIDTH:]) Sync_in2_PORTB=Signal(intbv(0)[WIDTH:]) INTERN_PORTC_OUT=Signal(intbv(0)[WIDTH:]) INTERN_PORTD_OUT=Signal(intbv(0)[WIDTH:]) @always(clk.posedge,rst.negedge) def IO_write_sync(): if rst==0: INTERN_PORTC_OUT.next=0 INTERN_PORTD_OUT.next=0 else: Sync_in1_PORTA.next=PORTA_IN Sync_in2_PORTA.next=Sync_in1_PORTA Sync_in1_PORTB.next=PORTB_IN Sync_in2_PORTB.next=Sync_in1_PORTB if we: if addr==2: INTERN_PORTC_OUT.next=din elif addr==3: INTERN_PORTD_OUT.next=din @always_comb def IO_read(): PORTC_OUT.next=INTERN_PORTC_OUT PORTD_OUT.next=INTERN_PORTD_OUT dout.next = 0 if addr==0: dout.next = Sync_in2_PORTA if addr==1: dout.next = Sync_in2_PORTB if addr==2: dout.next = INTERN_PORTC_OUT if addr==3: dout.next = INTERN_PORTD_OUT return IO_write_sync,IO_read def Processor(clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,CPU_PROGRAM=GLOBAL_PROGRAM,CPU_CONSTANTS=GLOBAL_CONSTANTS,VAR_BITWIDTH=32,VAR_DEPTH=20,STACK_SIZE=GLOBAL_STACK_SIZE): #### helping signals EnableJump=Signal(bool(0)) JumpValue=Signal(intbv(0)[8:]) #### Programm Memory Signals Opcode=Signal(intbv(0)[8:]) Arg1=Signal(intbv(0)[8:]) Arg2=Signal(intbv(0)[8:]) ProgramCounter=Signal(intbv(0,min=0,max=len(CPU_main.func_code.co_code))) #### Constants Memory Signals ConstantsData=Signal(intbv(0)[VAR_BITWIDTH:]) ConstantsAddr=Signal(intbv(0,min=0,max=len(CPU_CONSTANTS))) #### Programm Variables RAM Signals Varibles_DataOut=Signal(intbv(0)[VAR_BITWIDTH:]) Variables_DataIn=Signal(intbv(0)[VAR_BITWIDTH:]) VariablesAddr=Signal(intbv(0,min=0,max=VAR_DEPTH)) Variables_we=Signal(bool(0)) #### Stack Signals # STACK_SIZE Stack_DataIn=Signal(intbv(0)[VAR_BITWIDTH:]) StackValue0=Signal(intbv(0)[VAR_BITWIDTH:]) StackOP=Signal(intbv(0,min=0,max=GLOBAL_NUMBERSTACK_OPS)) StackOP_CMPmode=Signal(intbv(0,min=0,max=len(dis.cmp_op))) #### IO Module Signals IO_MODULE_STARTADDRESSES=4 #IO_MODULE_ADDRESBITS=int(math.log(IO_MODULE_STARTADDRESSES,2)+1)-1 IO_DataOut=Signal(intbv(0)[VAR_BITWIDTH:]) IO_DataIn=Signal(intbv(0)[VAR_BITWIDTH:]) IO_addr=Signal(intbv(0,min=0,max=IO_MODULE_STARTADDRESSES)) IO_we=Signal(bool(0)) ####Variables RAM instantiation VariablesRAM_inst=RAM(Varibles_DataOut, Variables_DataIn, VariablesAddr, Variables_we, clk, WORD_SZ=VAR_BITWIDTH, DEPTH=VAR_DEPTH) ###Programm Code Memory instantiation ProgrammCode_inst=ProgrammROM(Opcode,Arg1,Arg2,ProgramCounter,CPU_PROGRAM) ###Constants memory instantiation ConstantsROM_inst=ROM(ConstantsData,ConstantsAddr,CPU_CONSTANTS) ###The stack TheStack_inst=Stack(clk,rst,StackValue0,Stack_DataIn,StackOP,StackOP_CMPmode, WORD_SZ=VAR_BITWIDTH,SIZE=STACK_SIZE) ###I/O Module instantiation IOModule_inst=IOModule(clk,rst,IO_DataOut,IO_DataIn,IO_addr,IO_we,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,WIDTH=VAR_BITWIDTH) @always(clk.posedge,rst.negedge) def seq_logic(): if rst == 0: ##### ProgramCounter Part ######## ProgramCounter.next = 0 ##### END ProgramCounter Part ######## else: ##### ProgramCounter Part ######## if EnableJump==True:#StackValue0==bool(1)#Opcode==dis.opmap['POP_JUMP_IF_FALSE'] or Opcode==dis.opmap['POP_JUMP_IF_TRUE'] ProgramCounter.next=JumpValue else: if Opcode >= HAVE_ARGUMENT: ProgramCounter.next = ProgramCounter+3 else: ProgramCounter.next = ProgramCounter+1 ##### END ProgramCounter Part ######## ##### Opcode handling############# @always_comb def comb_logic(): JumpValue.next=0 EnableJump.next=False ConstantsAddr.next=0 StackOP.next=STACK_NOP StackOP_CMPmode.next=0 Stack_DataIn.next=0 Variables_we.next=False VariablesAddr.next=0 Variables_DataIn.next=StackValue0 IO_we.next=False IO_addr.next=0 IO_DataIn.next=StackValue0 if Opcode==23: #dis.opmap['BINARY_ADD']: # 23, StackOP.next=STACK_ADD elif Opcode==64: #dis.opmap['BINARY_AND']: # 64, StackOP.next=STACK_ADD elif Opcode==62: #dis.opmap['BINARY_LSHIFT']: #: 62, StackOP.next=STACK_LSHIFT elif Opcode==66: #dis.opmap['BINARY_OR']: #: 66, StackOP.next=STACK_OR elif Opcode==63: #dis.opmap['BINARY_RSHIFT']: #: 63, StackOP.next=STACK_RSHIFT elif Opcode==24: #dis.opmap['BINARY_SUBTRACT']: #: 24, StackOP.next=STACK_SUB elif Opcode==65: #dis.opmap['BINARY_XOR']: #: 65, StackOP.next=STACK_XOR elif Opcode==107: #dis.opmap['COMPARE_OP']: #: 107, StackOP.next=STACK_CMP StackOP_CMPmode.next=Arg1 elif Opcode==4: #dis.opmap[''DUP_TOP']: # 4 StackOP.next=STACK_DUP_TOP elif Opcode==113: #dis.opmap['JUMP_ABSOLUTE'] : #: 113, EnableJump.next=True JumpValue.next=Arg1 elif Opcode==110: #dis.opmap['JUMP_FORWARD']: #: 110, EnableJump.next=True JumpValue.next=ProgramCounter+3+Arg1 elif Opcode==111: #dis.opmap['JUMP_IF_FALSE_OR_POP']: #: 111, if StackValue0==0: EnableJump.next=True JumpValue.next=Arg1 elif Opcode==112: #dis.opmap['JUMP_IF_TRUE_OR_POP']: #: 112, if StackValue0==1: JumpValue.next=Arg1 EnableJump.next=True else: StackOP.next=STACK_POP elif Opcode==100: #dis.opmap['LOAD_CONST']: #: 100, StackOP.next=STACK_LOAD Stack_DataIn.next=ConstantsData ConstantsAddr.next=Arg1 elif Opcode==124: #dis.opmap['LOAD_FAST']: #: 124, StackOP.next=STACK_LOAD VariablesAddr.next=Arg1 Stack_DataIn.next=Varibles_DataOut elif Opcode==116: #dis.opmap['LOAD_GLOBAL']: 116, StackOP.next=STACK_LOAD IO_addr.next=Arg1 Stack_DataIn.next=IO_DataOut elif Opcode==97: #dis.opmap[''STORE_GLOBAL']: 97, IO_we.next=True IO_addr.next=Arg1 elif Opcode==114: #dis.opmap['POP_JUMP_IF_FALSE']: #: 114, StackOP.next=STACK_POP if StackValue0==0: JumpValue.next=Arg1 EnableJump.next=True elif Opcode==115: #dis.opmap['POP_JUMP_IF_TRUE']: #: 115, StackOP.next=STACK_POP if StackValue0==1: JumpValue.next=Arg1 EnableJump.next=True elif Opcode==1: #dis.opmap['POP_TOP'] StackOP.next=STACK_POP elif Opcode==5: #dis.opmap['ROT_FOUR']: #: 5, StackOP.next=STACK_ROT_FOUR elif Opcode==3: #dis.opmap['ROT_THREE']: #: 3, StackOP.next=STACK_ROT_THREE elif Opcode==2: #dis.opmap['ROT_TWO']: #: 2, StackOP.next=STACK_ROT_TWO elif Opcode==125: #dis.opmap['STORE_FAST']: #: 125, Variables_we.next=True VariablesAddr.next=Arg1 elif Opcode==15: #dis.opmap['UNARY_INVERT']: #:15 StackOP.next=STACK_INVERT elif Opcode==11: #dis.opmap['UNARY_NEGATIVE']: #: 11, StackOP.next=STACK_NEGATIVE elif Opcode==12: #dis.opmap['UNARY_NOT']: #: 12, StackOP.next=STACK_NOT elif Opcode==10: #dis.opmap['UNARY_POSITIVE']: #: 10, StackOP.next=STACK_POSITIVE elif Opcode==120: #dis.opmap['SETUP_LOOP']: # TODO?? StackOP.next=STACK_NOP else: StackOP.next=STACK_NOP #raise ValueError("Unsuported Command:"+str(Opcode)) print "Comand not supported:",Opcode return seq_logic,comb_logic,VariablesRAM_inst,ProgrammCode_inst,ConstantsROM_inst,TheStack_inst,IOModule_inst def convert(): WORD_SZ=8 DEPTH=16384 we, clk = [Signal(bool(0)) for i in range(2)] dout = Signal(intbv(0)[WORD_SZ:]) din = Signal(intbv(0)[WORD_SZ:]) addr = Signal(intbv(0)[16:]) toVHDL(RAM, dout, din, addr, we,clk,WORD_SZ,DEPTH) def Processor_TESTBENCH(): rst, clk = [Signal(bool(0)) for i in range(2)] PORTA_IN=Signal(intbv(0)[32:]) PORTB_IN=Signal(intbv(0)[32:]) PORTC_OUT=Signal(intbv(0)[32:]) PORTD_OUT=Signal(intbv(0)[32:]) toVHDL(Processor,clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT) Processor_inst=Processor(clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT) @always(delay(10)) def clkgen(): clk.next = not clk @instance def stimulus(): print "#"*10+"Reseting"+"#"*10 rst.next=0 print "#"*10+"Setting PORTA_IN too 0"+"#"*10 PORTA_IN.next=0 for i in range(3): yield clk.negedge print "#"*10+"Release Reset"+"#"*10 rst.next=1 for i in range(200): yield clk.negedge print "#"*10+"Setting PORTA_IN too 1"+"#"*10 PORTA_IN.next=1 for i in range(200): yield clk.negedge PORTA_IN.next=0 for i in range(500): yield clk.negedge raise StopSimulation @instance def Monitor_PORTC(): print "\t\tPortC:",PORTC_OUT while 1: yield PORTC_OUT print "\t\tPortC:",PORTC_OUT @instance def Monitor_PORTD(): print "PortD:",PORTD_OUT while 1: yield PORTD_OUT print "PortD:",PORTD_OUT return clkgen,Processor_inst,stimulus,Monitor_PORTC,Monitor_PORTD #tb = traceSignals(Processor_TESTBENCH) sim = Simulation(Processor_TESTBENCH()) sim.run() #convert() #def simulate(timesteps): # tb = traceSignals(test_dffa) # sim = Simulation(tb) # sim.run(timesteps) #simulate(20000) |
From: Christopher L. <loz...@fr...> - 2012-02-04 21:01:40
|
# # Description: Python Hardware Processor # This Code implements a Hardware CPU in myhdl. The code for the cpu is directly written in python # and since the hardware description is also in python, the programm code is automatically into the design # I love it. People like the author make me happy to have subscribed to this mailing list for the last year. Actually I had a vague idea like this in the back of my mind, but to actually see it in code is awesome. Makes it so much more concrete. Sir, I am sure that you have a lot of work to do, but if you go do a graphical image of the hardware architecture and data flow that would help me enormously to understand it. Trying to understand the code is hard work. How fast is this device compared to a traditional CPU? And then here is the million dollar question. How would you change the python language to better fit an FPGA? |
From: Christopher F. <chr...@gm...> - 2012-02-04 22:12:20
|
Norbo, If you like you can create a project page on the MyHDL wiki space. Or you might want to share the code via BitBucket or GitHub. Regards, Chris On 2/4/12 7:48 AM, Norbo wrote: > To show where i am at: > ##################################### > # File: Core.py > # Author: Norbert Feurle > # Date: 4.2.2012 > # > # Description: Python Hardware Processor > # This Code implements a Hardware CPU in myhdl. The code for the cpu is > directly written in python > # and since the hardware description is also in python, the programmcode > is automatically into the design > # The cool thing is that by this approach only memory and stack hardware > is allocated in Hardware which is > # really needed. Simulation of the code on the cpu running is no problem. > (only python needed!) > # The bytecode of python is executed at the cpu at one instruction per > cycle > # By now only simple bytecode instructions are supported > # You can simply instantiate more Hardware CPUs on an FPGA with different > program code to make it run parallel > # > # License: Pro life licence. > # You are not allowed to this code for any purpose which is in any kind > disrespectfully to life and/or freedom > # In such a case it remains my property > # for example: You are not allowed to build weapons, or large-scale > animal husbandry automation equipment or anything > # that is used to harm, destroy or is used to frighten living beings at > an unacceptable rate, or build hardware > # with it where te workers dont get paid appropriate, or any process > where the waste issue isnt solved in a sustainable way, # etc.. > # > # If you use it respectfully you are allowed to use it for free and are > welcome to contribute with your changes/extensions > ################################################################################################# > > > > ######################################################################################## > #### Limitations: > #### no lists, no dicts no tuples, no float, no complex numbers, > #### no classmembers,no function calls, no multiplication, no exeptions, > no for x in xxx:, etc. > ######################################################################################## > ### What is supported: > ### ints(with x bits), no other python types > ### simple if and while and assignments > ### Operators: +, ^ , |,&. - (minus doesent work yet becaus i never used > signed (big TODO)) > ### Simple Digital IO with PORTs > ### And of corse some bugs > ######################################################################################## > > ##### The main programm for the python hardware porcessor to execute #### > def CPU_main(): > ## Reserves for IO Module ### > global PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT > PORTA_IN=0 #needs to bee here to reserve the right addresses (0 is > written to nowhere) > PORTB_IN=0 > PORTC_OUT=0 > PORTD_OUT=0 > ################# > x=0 > while 1: > x=x+1 > if PORTA_IN==1: > PORTC_OUT= PORTC_OUT^1 > if x<20: > PORTD_OUT=x > elif x>=20 and x<25: > PORTD_OUT=2**30+x > else: > PORTD_OUT=x > ##### End of the main programm #### > > > from myhdl import * > import math > import dis > HAVE_ARGUMENT=dis.HAVE_ARGUMENT > GLOBAL_PROGRAM=tuple([ord(i) for i in CPU_main.func_code.co_code]) + > (0,0,) #because arguments are also read > GLOBAL_CONSTANTS=(0,)+CPU_main.func_code.co_consts[1:] # because constant > None is on address 0 but cpu only supports int > GLOBAL_STACK_SIZE=CPU_main.func_code.co_stacksize > > GLOBAL_NUMBERSTACK_OPS=19 > STACK_NOP,STACK_ADD,STACK_POSITIVE,STACK_NOT,STACK_NEGATIVE,STACK_INVERT,STACK_RSHIFT,STACK_LSHIFT,STACK_AND,STACK_SUB,STACK_OR,STACK_XOR,STACK_POP,STACK_LOAD,STACK_CMP,STACK_ROT_FOUR, > STACK_ROT_TWO, STACK_ROT_THREE,STACK_DUP_TOP=range(GLOBAL_NUMBERSTACK_OPS) > > > def RAM(dout, din, addr, we, clk, WORD_SZ=8, DEPTH=16384): > """ > > """ > mem = [Signal(intbv(0)[WORD_SZ:]) for i in range(DEPTH)] > > @always(clk.posedge) > def write(): > if we: > mem[int(addr)].next = din > > @always_comb > def read(): > dout.next = mem[int(addr)] > > return write,read > > > def ROM(dout,addr,CONTENT): > @always_comb > def rom_logic(): > dout.next= CONTENT[int(addr)] > > return rom_logic > > def ProgrammROM(Opcode,Arg1,Arg2,addr,CONTENT): > @always_comb > def progrom_logic(): > Opcode.next= CONTENT[int(addr)] > Arg1.next= CONTENT[int(addr+1)] > Arg2.next= CONTENT[int(addr+2)] > > return progrom_logic > > def > Stack(clk,rst,TopData_Out,Data_In,StackOP,CMPmode,WORD_SZ=32,SIZE=GLOBAL_STACK_SIZE): > Stack_mem = [Signal(intbv(0)[WORD_SZ:]) for i in range(SIZE)] > > Next_TSO_Data=Signal(intbv(0)[WORD_SZ:]) > TOS_Data=Signal(intbv(0)[WORD_SZ:]) > TOS1_Data=Signal(intbv(0)[WORD_SZ:]) > TOS2_Data=Signal(intbv(0)[WORD_SZ:]) > > TOS_Data_RD=Signal(intbv(0)[WORD_SZ:]) > TOS1_Data_RD=Signal(intbv(0)[WORD_SZ:]) > TOS2_Data_RD=Signal(intbv(0)[WORD_SZ:]) > > TOS_pointer_next=Signal(intbv(0,min=0,max=SIZE)) > TOS_pointer= Signal(intbv(0,min=0,max=SIZE)) > TOS1_pointer= Signal(intbv(0,min=0,max=SIZE)) > TOS2_pointer= Signal(intbv(0,min=0,max=SIZE)) > #TOS3_pointer= Signal(intbv(0,min=0,max=SIZE)) > > enable_stackpointer_increase=Signal(bool(0)) > enable_stackpointer_deacrease=Signal(bool(0)) > > @always(clk.posedge,rst.negedge) > def seq_logic(): > if rst == 0: > TOS_pointer_next.next=0 > TOS_pointer.next=0 > TOS1_pointer.next=0 > TOS2_pointer.next=0 > #TOS3_pointer.next=0 > for indexer in range(SIZE): > Stack_mem[int(indexer)].next=0 > else: > if enable_stackpointer_increase: > TOS_pointer_next.next=(TOS_pointer_next+1)% SIZE > TOS_pointer.next=TOS_pointer_next > TOS1_pointer.next=TOS_pointer > TOS2_pointer.next=TOS1_pointer > if enable_stackpointer_deacrease: > if TOS2_pointer==0: > TOS2_pointer.next=SIZE-1 > else: > TOS2_pointer.next=TOS2_pointer-1 > > TOS1_pointer.next=TOS2_pointer > TOS_pointer.next=TOS1_pointer > TOS_pointer_next.next=TOS_pointer > #Stackpointer.next=Stackpointer_next > > #attention if stacksize is to smalll the lower one gets overwritten > #so the ordering is important > # TODO: stacksize==1 would not work > Stack_mem[int(TOS2_pointer)].next=TOS2_Data > Stack_mem[int(TOS1_pointer)].next=TOS1_Data > Stack_mem[int(TOS_pointer)].next=TOS_Data > Stack_mem[int(TOS_pointer_next)].next=Next_TSO_Data > > > > @always_comb > def comb_logic(): > Next_TSO_Data.next=Stack_mem[int(TOS_pointer_next)] > TOS_Data.next=Stack_mem[int(TOS_pointer)] > TOS1_Data.next=Stack_mem[int(TOS1_pointer)] > TOS2_Data.next=Stack_mem[int(TOS2_pointer)] > > enable_stackpointer_increase.next=1 > enable_stackpointer_deacrease.next=0 > > if StackOP==STACK_NOP: > enable_stackpointer_increase.next=0 > elif StackOP==STACK_ADD: > Next_TSO_Data.next=TOS1_Data_RD+TOS_Data_RD > elif StackOP==STACK_POSITIVE: #??? > Next_TSO_Data.next=TOS_Data_RD > elif StackOP==STACK_NOT: > Next_TSO_Data.next=TOS_Data_RD > elif StackOP==STACK_NEGATIVE: > Next_TSO_Data.next=-TOS_Data_RD > elif StackOP==STACK_INVERT: > Next_TSO_Data.next=~TOS_Data_RD > elif StackOP==STACK_RSHIFT: > Next_TSO_Data.next=TOS1_Data_RD>>TOS_Data_RD > elif StackOP==STACK_LSHIFT: > Next_TSO_Data.next=TOS1_Data_RD<<TOS_Data_RD > elif StackOP==STACK_AND: > Next_TSO_Data.next=TOS1_Data_RD&TOS_Data_RD > elif StackOP==STACK_SUB: > Next_TSO_Data.next=TOS1_Data_RD-TOS_Data_RD > elif StackOP==STACK_OR: > Next_TSO_Data.next=TOS1_Data_RD|TOS_Data_RD > elif StackOP==STACK_XOR: > Next_TSO_Data.next=TOS1_Data_RD^TOS_Data_RD > elif StackOP==STACK_POP: > enable_stackpointer_increase.next=0 > enable_stackpointer_deacrease.next=1 > elif StackOP==STACK_LOAD: > Next_TSO_Data.next=Data_In > > elif StackOP==STACK_ROT_TWO: > enable_stackpointer_increase.next=0 > TOS_Data.next=TOS1_Data_RD > TOS1_Data.next=TOS_Data_RD > elif StackOP==STACK_ROT_THREE: > enable_stackpointer_increase.next=0 > TOS_Data.next=TOS1_Data_RD > TOS1_Data.next=TOS2_Data_RD > TOS2_Data.next=TOS_Data_RD > #elif StackOP==STACK_ROT_FOUR: ##TODO > #TOS_Data.next=Stack_mem[int(TOS_pointer)] > # TOS1_Data.next=Stack_mem[int(TOS1_pointer)] > # TOS2_Data.next=Stack_mem[int(TOS2_pointer)] > elif StackOP==STACK_DUP_TOP: > Next_TSO_Data.next=TOS_Data_RD > elif StackOP==STACK_CMP: > if CMPmode==0: #operator< > if TOS1_Data_RD<TOS_Data_RD: > Next_TSO_Data.next=1 > else: > Next_TSO_Data.next=0 > if CMPmode==1: #operator<= > if TOS1_Data_RD<=TOS_Data_RD: > Next_TSO_Data.next=1 > else: > Next_TSO_Data.next=0 > if CMPmode==2: #operator == > if TOS1_Data_RD==TOS_Data_RD: > Next_TSO_Data.next=1 > else: > Next_TSO_Data.next=0 > if CMPmode==3: #operator != > if TOS1_Data_RD!=TOS_Data_RD: > Next_TSO_Data.next=1 > else: > Next_TSO_Data.next=0 > if CMPmode==4: #operator> > if TOS1_Data_RD>TOS_Data_RD: > Next_TSO_Data.next=1 > else: > Next_TSO_Data.next=0 > if CMPmode==5: #operator>= > if TOS1_Data_RD>=TOS_Data_RD: > Next_TSO_Data.next=1 > else: > Next_TSO_Data.next=0 > else: > enable_stackpointer_increase.next=0 > > > > @always_comb > def comb_logic2(): > TOS_Data_RD.next=Stack_mem[int(TOS_pointer)] > TOS1_Data_RD.next=Stack_mem[int(TOS1_pointer)] > TOS2_Data_RD.next=Stack_mem[int(TOS2_pointer)] > TopData_Out.next=Stack_mem[int(TOS_pointer)] > > return seq_logic,comb_logic,comb_logic2 > > def > IOModule(clk,rst,dout,din,addr,we,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,WIDTH=32): > Sync_in1_PORTA=Signal(intbv(0)[WIDTH:]) > Sync_in2_PORTA=Signal(intbv(0)[WIDTH:]) > Sync_in1_PORTB=Signal(intbv(0)[WIDTH:]) > Sync_in2_PORTB=Signal(intbv(0)[WIDTH:]) > > INTERN_PORTC_OUT=Signal(intbv(0)[WIDTH:]) > INTERN_PORTD_OUT=Signal(intbv(0)[WIDTH:]) > @always(clk.posedge,rst.negedge) > def IO_write_sync(): > if rst==0: > INTERN_PORTC_OUT.next=0 > INTERN_PORTD_OUT.next=0 > else: > Sync_in1_PORTA.next=PORTA_IN > Sync_in2_PORTA.next=Sync_in1_PORTA > > Sync_in1_PORTB.next=PORTB_IN > Sync_in2_PORTB.next=Sync_in1_PORTB > > if we: > if addr==2: > INTERN_PORTC_OUT.next=din > elif addr==3: > INTERN_PORTD_OUT.next=din > > > @always_comb > def IO_read(): > PORTC_OUT.next=INTERN_PORTC_OUT > PORTD_OUT.next=INTERN_PORTD_OUT > dout.next = 0 > if addr==0: > dout.next = Sync_in2_PORTA > if addr==1: > dout.next = Sync_in2_PORTB > if addr==2: > dout.next = INTERN_PORTC_OUT > if addr==3: > dout.next = INTERN_PORTD_OUT > > return IO_write_sync,IO_read > > > def > Processor(clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,CPU_PROGRAM=GLOBAL_PROGRAM,CPU_CONSTANTS=GLOBAL_CONSTANTS,VAR_BITWIDTH=32,VAR_DEPTH=20,STACK_SIZE=GLOBAL_STACK_SIZE): > > > #### helping signals > EnableJump=Signal(bool(0)) > JumpValue=Signal(intbv(0)[8:]) > > #### Programm Memory Signals > Opcode=Signal(intbv(0)[8:]) > Arg1=Signal(intbv(0)[8:]) > Arg2=Signal(intbv(0)[8:]) > ProgramCounter=Signal(intbv(0,min=0,max=len(CPU_main.func_code.co_code))) > > #### Constants Memory Signals > ConstantsData=Signal(intbv(0)[VAR_BITWIDTH:]) > ConstantsAddr=Signal(intbv(0,min=0,max=len(CPU_CONSTANTS))) > > #### Programm Variables RAM Signals > Varibles_DataOut=Signal(intbv(0)[VAR_BITWIDTH:]) > Variables_DataIn=Signal(intbv(0)[VAR_BITWIDTH:]) > VariablesAddr=Signal(intbv(0,min=0,max=VAR_DEPTH)) > Variables_we=Signal(bool(0)) > > #### Stack Signals > # STACK_SIZE > Stack_DataIn=Signal(intbv(0)[VAR_BITWIDTH:]) > StackValue0=Signal(intbv(0)[VAR_BITWIDTH:]) > StackOP=Signal(intbv(0,min=0,max=GLOBAL_NUMBERSTACK_OPS)) > StackOP_CMPmode=Signal(intbv(0,min=0,max=len(dis.cmp_op))) > > #### IO Module Signals > IO_MODULE_STARTADDRESSES=4 > #IO_MODULE_ADDRESBITS=int(math.log(IO_MODULE_STARTADDRESSES,2)+1)-1 > IO_DataOut=Signal(intbv(0)[VAR_BITWIDTH:]) > IO_DataIn=Signal(intbv(0)[VAR_BITWIDTH:]) > IO_addr=Signal(intbv(0,min=0,max=IO_MODULE_STARTADDRESSES)) > IO_we=Signal(bool(0)) > > ####Variables RAM instantiation > VariablesRAM_inst=RAM(Varibles_DataOut, Variables_DataIn, > VariablesAddr, Variables_we, clk, WORD_SZ=VAR_BITWIDTH, DEPTH=VAR_DEPTH) > > ###Programm Code Memory instantiation > ProgrammCode_inst=ProgrammROM(Opcode,Arg1,Arg2,ProgramCounter,CPU_PROGRAM) > > ###Constants memory instantiation > ConstantsROM_inst=ROM(ConstantsData,ConstantsAddr,CPU_CONSTANTS) > > ###The stack > TheStack_inst=Stack(clk,rst,StackValue0,Stack_DataIn,StackOP,StackOP_CMPmode, > WORD_SZ=VAR_BITWIDTH,SIZE=STACK_SIZE) > > ###I/O Module instantiation > IOModule_inst=IOModule(clk,rst,IO_DataOut,IO_DataIn,IO_addr,IO_we,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,WIDTH=VAR_BITWIDTH) > > @always(clk.posedge,rst.negedge) > def seq_logic(): > if rst == 0: > ##### ProgramCounter Part ######## > ProgramCounter.next = 0 > ##### END ProgramCounter Part ######## > > else: > ##### ProgramCounter Part ######## > if > EnableJump==True:#StackValue0==bool(1)#Opcode==dis.opmap['POP_JUMP_IF_FALSE'] > or Opcode==dis.opmap['POP_JUMP_IF_TRUE'] > ProgramCounter.next=JumpValue > else: > if Opcode>= HAVE_ARGUMENT: > ProgramCounter.next = ProgramCounter+3 > else: > ProgramCounter.next = ProgramCounter+1 > ##### END ProgramCounter Part ######## > > ##### Opcode handling############# > @always_comb > def comb_logic(): > > JumpValue.next=0 > EnableJump.next=False > > ConstantsAddr.next=0 > > StackOP.next=STACK_NOP > StackOP_CMPmode.next=0 > Stack_DataIn.next=0 > > Variables_we.next=False > VariablesAddr.next=0 > Variables_DataIn.next=StackValue0 > > IO_we.next=False > IO_addr.next=0 > IO_DataIn.next=StackValue0 > > if Opcode==23: #dis.opmap['BINARY_ADD']: # 23, > StackOP.next=STACK_ADD > elif Opcode==64: #dis.opmap['BINARY_AND']: # 64, > StackOP.next=STACK_ADD > elif Opcode==62: #dis.opmap['BINARY_LSHIFT']: #: 62, > StackOP.next=STACK_LSHIFT > elif Opcode==66: #dis.opmap['BINARY_OR']: #: 66, > StackOP.next=STACK_OR > elif Opcode==63: #dis.opmap['BINARY_RSHIFT']: #: 63, > StackOP.next=STACK_RSHIFT > elif Opcode==24: #dis.opmap['BINARY_SUBTRACT']: #: 24, > StackOP.next=STACK_SUB > elif Opcode==65: #dis.opmap['BINARY_XOR']: #: 65, > StackOP.next=STACK_XOR > elif Opcode==107: #dis.opmap['COMPARE_OP']: #: 107, > StackOP.next=STACK_CMP > StackOP_CMPmode.next=Arg1 > elif Opcode==4: #dis.opmap[''DUP_TOP']: # 4 > StackOP.next=STACK_DUP_TOP > elif Opcode==113: #dis.opmap['JUMP_ABSOLUTE'] : #: 113, > EnableJump.next=True > JumpValue.next=Arg1 > elif Opcode==110: #dis.opmap['JUMP_FORWARD']: #: 110, > EnableJump.next=True > JumpValue.next=ProgramCounter+3+Arg1 > elif Opcode==111: #dis.opmap['JUMP_IF_FALSE_OR_POP']: #: 111, > if StackValue0==0: > EnableJump.next=True > JumpValue.next=Arg1 > elif Opcode==112: #dis.opmap['JUMP_IF_TRUE_OR_POP']: #: 112, > if StackValue0==1: > JumpValue.next=Arg1 > EnableJump.next=True > else: > StackOP.next=STACK_POP > elif Opcode==100: #dis.opmap['LOAD_CONST']: #: 100, > StackOP.next=STACK_LOAD > Stack_DataIn.next=ConstantsData > ConstantsAddr.next=Arg1 > elif Opcode==124: #dis.opmap['LOAD_FAST']: #: 124, > StackOP.next=STACK_LOAD > VariablesAddr.next=Arg1 > Stack_DataIn.next=Varibles_DataOut > elif Opcode==116: #dis.opmap['LOAD_GLOBAL']: 116, > StackOP.next=STACK_LOAD > IO_addr.next=Arg1 > Stack_DataIn.next=IO_DataOut > elif Opcode==97: #dis.opmap[''STORE_GLOBAL']: 97, > IO_we.next=True > IO_addr.next=Arg1 > elif Opcode==114: #dis.opmap['POP_JUMP_IF_FALSE']: #: 114, > StackOP.next=STACK_POP > if StackValue0==0: > JumpValue.next=Arg1 > EnableJump.next=True > elif Opcode==115: #dis.opmap['POP_JUMP_IF_TRUE']: #: 115, > StackOP.next=STACK_POP > if StackValue0==1: > JumpValue.next=Arg1 > EnableJump.next=True > elif Opcode==1: #dis.opmap['POP_TOP'] > StackOP.next=STACK_POP > elif Opcode==5: #dis.opmap['ROT_FOUR']: #: 5, > StackOP.next=STACK_ROT_FOUR > elif Opcode==3: #dis.opmap['ROT_THREE']: #: 3, > StackOP.next=STACK_ROT_THREE > elif Opcode==2: #dis.opmap['ROT_TWO']: #: 2, > StackOP.next=STACK_ROT_TWO > elif Opcode==125: #dis.opmap['STORE_FAST']: #: 125, > Variables_we.next=True > VariablesAddr.next=Arg1 > elif Opcode==15: #dis.opmap['UNARY_INVERT']: #:15 > StackOP.next=STACK_INVERT > elif Opcode==11: #dis.opmap['UNARY_NEGATIVE']: #: 11, > StackOP.next=STACK_NEGATIVE > elif Opcode==12: #dis.opmap['UNARY_NOT']: #: 12, > StackOP.next=STACK_NOT > elif Opcode==10: #dis.opmap['UNARY_POSITIVE']: #: 10, > StackOP.next=STACK_POSITIVE > elif Opcode==120: #dis.opmap['SETUP_LOOP']: # TODO?? > StackOP.next=STACK_NOP > else: > StackOP.next=STACK_NOP > #raise ValueError("Unsuported Command:"+str(Opcode)) > print "Comand not supported:",Opcode > > return > seq_logic,comb_logic,VariablesRAM_inst,ProgrammCode_inst,ConstantsROM_inst,TheStack_inst,IOModule_inst > > > def convert(): > WORD_SZ=8 > DEPTH=16384 > > we, clk = [Signal(bool(0)) for i in range(2)] > dout = Signal(intbv(0)[WORD_SZ:]) > din = Signal(intbv(0)[WORD_SZ:]) > addr = Signal(intbv(0)[16:]) > > toVHDL(RAM, dout, din, addr, we,clk,WORD_SZ,DEPTH) > > > def Processor_TESTBENCH(): > rst, clk = [Signal(bool(0)) for i in range(2)] > PORTA_IN=Signal(intbv(0)[32:]) > PORTB_IN=Signal(intbv(0)[32:]) > PORTC_OUT=Signal(intbv(0)[32:]) > PORTD_OUT=Signal(intbv(0)[32:]) > > toVHDL(Processor,clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT) > Processor_inst=Processor(clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT) > > > > @always(delay(10)) > def clkgen(): > clk.next = not clk > > @instance > def stimulus(): > print "#"*10+"Reseting"+"#"*10 > rst.next=0 > print "#"*10+"Setting PORTA_IN too 0"+"#"*10 > PORTA_IN.next=0 > > for i in range(3): > yield clk.negedge > print "#"*10+"Release Reset"+"#"*10 > rst.next=1 > > for i in range(200): > yield clk.negedge > > print "#"*10+"Setting PORTA_IN too 1"+"#"*10 > PORTA_IN.next=1 > for i in range(200): > yield clk.negedge > > PORTA_IN.next=0 > for i in range(500): > yield clk.negedge > > raise StopSimulation > > @instance > def Monitor_PORTC(): > print "\t\tPortC:",PORTC_OUT > while 1: > yield PORTC_OUT > print "\t\tPortC:",PORTC_OUT > > @instance > def Monitor_PORTD(): > print "PortD:",PORTD_OUT > while 1: > yield PORTD_OUT > print "PortD:",PORTD_OUT > > return clkgen,Processor_inst,stimulus,Monitor_PORTC,Monitor_PORTD > > #tb = traceSignals(Processor_TESTBENCH) > sim = Simulation(Processor_TESTBENCH()) > sim.run() > > #convert() > > #def simulate(timesteps): > # tb = traceSignals(test_dffa) > # sim = Simulation(tb) > # sim.run(timesteps) > > #simulate(20000) > > > ------------------------------------------------------------------------------ > Try before you buy = See our experts in action! > The most comprehensive online learning library for Microsoft developers > is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3, > Metro Style Apps, more. Free future releases when you subscribe now! > http://p.sf.net/sfu/learndevnow-dev2 |
From: garyr <ga...@fi...> - 2012-02-05 17:34:03
|
FYI - a recently published book on microprocessor design and Verilog. http://www.cc-webshop.com/ ----- Original Message ----- From: "Christopher Felton" <chr...@gm...> To: <myh...@li...> Sent: Saturday, February 04, 2012 2:11 PM Subject: Re: [myhdl-list] Python Hardware Processor > Norbo, > > If you like you can create a project page on the MyHDL wiki space. Or > you might want to share the code via BitBucket or GitHub. > > Regards, > Chris > |
From: Norbo <Nor...@gm...> - 2012-02-06 10:45:05
|
Yeah, creating a wiki page would be nice, but is this possible, since Jan Decaluwe is unfortunately right now out of business. The Site says: """How to get an account: To request an account, please send an email to Jan Decaluwe. Please add some info that demonstrates your experience level with MyHDL. """ greetings Norbo |
From: Christopher F. <chr...@gm...> - 2012-02-06 12:28:07
|
On 2/6/2012 4:44 AM, Norbo wrote: > Yeah, creating a wiki page would be nice, but is this possible, since Jan > Decaluwe is unfortunately right now out of business. > > The Site says: > > """How to get an account: > > To request an account, please send an email to Jan Decaluwe. Please add > some info that demonstrates your experience level with MyHDL. """ > > > greetings > Norbo > You are right, it might be a little difficult to create a wiki page right now. You can still send a request but it might be awhile before it is acknowledged. Regards, Chris |
From: Christopher L. <loz...@fr...> - 2012-02-06 15:56:26
|
On 2/6/12 7:27 AM, Christopher Felton wrote: > You are right, it might be a little difficult to create a wiki page > right now. You can still send a request but it might be awhile before A second person with root privileges would be a really good idea, and protect us all against the risk of something happening to Jan Decaluwe. -- Regards Christopher Lozinski Check out my iPhone apps TextFaster and EmailFaster http://textfaster.com Expect a paradigm shift. http://MyHDL.org |
From: Norbo <Nor...@gm...> - 2012-03-04 12:08:43
|
Just got a bit further and i am now able to do function calls in the Python Hardware CPU, and a was able to reduce the logic usage of CPU a bit by shifting some registers into ram where the data needs an extra cycle be accessible. But still was able to maintain the one bytecode instruction per clk cycle execution. Now the cpu is able to execute python code like the following successfully (PORTA_IN,PORTB_IN and etc.. are the IO/Ports): With the following code the Cpu synthesises to approximatly 800 LUTS_4. (on lattice diamond 1.4 and Quartus web edition) I also needed to modify the bytecode a bit so that the functions are mapped correctly. Thereby i merge all the constants and all the globals of every function to a single place. (normaly every python function has its own constans memory and global name map) PREDEFINED_IO_ADDRESSES={'PORTA_IN':0,'PORTB_IN':1,'PORTC_OUT':2,'PORTD_OUT':3} #need to start at 0 global_argument=2 def kate(Cycles,argx): global PORTC_OUT,PORTD_OUT x=0 PORTD_OUT=PORTD_OUT+argx while x<Cycles: x=x+1 PORTC_OUT=PORTC_OUT^8 return 2 def delay(Cycles1,Cycles2): global PORTC_OUT x=5 while x<(Cycles1+Cycles2): x=x+1 PORTC_OUT=PORTC_OUT^4 x=0 while x<kate(1,global_argument): PORTC_OUT=PORTC_OUT^2 x=x+1 def CPU_main(): global PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT # at least output ports need to be defined as gloabals x=0 a=7 b=8 var_argument_b=3 var_argument_b=var_argument_b+1 while 1: x=x+1 #funcas(kkt(3)) # TODO calling a function with an function as an argument would not work delay(global_argument,var_argument_b) if PORTA_IN==1: PORTC_OUT=PORTC_OUT^1 if x<20: PORTD_OUT=x elif 20<=x<25: #or x>=20 and x<25: #both works PORTD_OUT=(2**7)+x else: PORTD_OUT=x a,b=b,a PORTD_OUT=a<<1 Tried it on hardware and i was able to blink an led on a lattic pico development board. With the following python code: (The Output pin was connected to the 5. pin of PORTD_OUT.) The Synthesis tools says that it can be run at 23 Mhz or so but i was running it at 12 MHz. PREDEFINED_IO_ADDRESSES={'PORTA_IN':0,'PORTB_IN':1,'PORTC_OUT':2,'PORTD_OUT':3} #need to start at 0 def wait(time): x=0 while x<100: td=0 x=x+1 while td<100: td=td+1 ss=0 while ss<time: ss=ss+1 def CPU_main(): global PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT while 1: PORTD_OUT=PORTD_OUT^16 wait(20) I just post the full code, right now its not very readable, ##################################### # File: pyHardwareCore.py # Author: Norbert Feurle # start Date: 2.2.2012 # latest Edit: 23.2.2012 # # Description: Python Hardware Processor # This Code implements a Hardware CPU in myhdl. The code for the CPU is drictly written in python # and since the hardware description is also in python, the programmcode is automatically loaded into the design # The cool thing is that with this approach only memory and stack hardware is allocated in Hardware which is # really needed. The Simulation of the cpu code on the hardware can be done in python only (only python needed! and of corse myhdl). # The bytecode of python is executed in the CPU with one instruction per cycle # You can simply instantiate more cores on an FPGA with different Programmcode to make them run in parallel # # License: Pro life licence. # You are not allowed to use this code for any purpose which is in any kind disrespectfully to life and/or freedom # In such a case it remains my property # for example: You are not allowed to build weapons, or large-scale animal husbandry automation equipment or anything # that is used to harm, destroy or is used to frighten living beeings at an unacceptable rate, or build hardware # with it where the workers dont get paid appropriate, or any process where the waste issue isnt solved in a sustainable way, # etc.. # If you use it respectfully you are allowed to use it for free and are welcome to contribute with your changes/extensions # You also have to keep this licence. ################################################################################################# ######################################################################################## #### Limitations: #### no lists, no dicts no tuples, no float, no complex numbers, etc. #### no classmembers,no multiplication, no exeptions, no for x in xxx:, etc. ######################################################################################## ### What is supported: #--------------------------------------------------- ### ints (with x bits), no other python types only plane ints ### if and while (comparisions with <,>, >=, <=,!=,== ) ### nested while loops up to CONST_LOOP_DEPTH (Constant Default value = 4) ### assignments to globals or local varibles from const, globals or define local variables ### Operators: +. -, ^ ,~, |, & ,<<,>> ### Simple Digital IOs over PORTS ### Function calls (with consts,and globals, or vars as argument, one intager as return value), no default arguments, no keyword arguments,no other functions as arguments ### up to MAX_NUMBER_FUNCTION_ARGUMENTS (Constant Default value = 10) arguments ### up to CONST_PC_STACK_DEPTH (Constant Default value=5) number of nested function calls ### up to VAR_MEM_DEPTH (Constant Default value=20) local variables ######################################################################################## ################################################################### ##### Bug Track / Upcomming Features list : #--------------------------------------------- # (done) Binary operations remove doesnt removes the operands from stack # (done but stack ram could be smaller) (but stack_mem is now very big, Solution -> add some cycles for rot_two, rot_three and rot_for and put stak into a RAM,maybe dualported ) dis.opmap['POP_BLOCK'] and dis.opmap['SETUP_LOOP'] clear stack # (halve done) Global memory initilisation in myhdl # (done)-> GLOBAL_CONTENT is set to (0,) in this case <- if there is no function exept CPU_main, toVHDL creates an error,probably because Global_mem is empty # (done) hasattr(eval(currentfunction.func_code.co_names[actual_Argument]), '__call__') througs exeption if PORTA_IN, etc is note defined global (defining PREDEFINED_IO_ADDRESSES should be enough) # (mostly done ) wheater make PORTS in a all positive range or all with -2**(x-1) to +2**(x-1) conversion from signed to unsigned # (done) Functions need to be able to use vars from var_mem as arguments (Dual ported var_mem) # TODO calling a function with an function as an argument would not work # TODO ROT_FOUR is not yet supported, adding a extra cycles is needed # TODO Test generated VHDL code, and on an FPGA, maybe cosimulation # TODO More Programm tests, Clean UP code, for example: eliminate magic numbers,general cleanup # (done) insert cycle after var_mem is read to make it possible to map it into ram, same for programm_code # TODO make jumps to addresses possible which exeed the size of VAR_BITWIDTH, for example to make a usable processor with WORD_SZ=4 bit # TODO generic addable multiplication support ########info: # ROT_TWO after SETUP_LOOP would not work but is kind of usless because the new stack block is empty ########################################## ################################################################# ####### Nice to haves: #----------------------------- # TODO maybe support List of ints with single integer subscription # TODO additional SPI,RS232,I2C,Timer,etc modules # TODO call functions from extern which are not loaded at startup # TODO dynamically generate I/O Ports on the processor dependend on PREDEFINED_IO_ADDRESSES ################################################################# ##### The main programm the cpu should execute #### PREDEFINED_IO_ADDRESSES={'PORTA_IN':0,'PORTB_IN':1,'PORTC_OUT':2,'PORTD_OUT':3} #need to start at 0 global_argument=2 def kate(Cycles,argx): global PORTC_OUT,PORTD_OUT x=0 PORTD_OUT=PORTD_OUT+argx while x<Cycles: x=x+1 PORTC_OUT=PORTC_OUT^8 return 2 def delay(Cycles1,Cycles2): global PORTC_OUT x=5 while x<(Cycles1+Cycles2): x=x+1 PORTC_OUT=PORTC_OUT^4 x=0 while x<kate(1,global_argument): PORTC_OUT=PORTC_OUT^2 x=x+1 def CPU_main(): global PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT # at least output ports need to be defined as gloabals x=0 a=7 b=8 var_argument_b=3 var_argument_b=var_argument_b+1 while 1: x=x+1 #funcas(kkt(3)) # TODO calling a function with an function as an argument would not work delay(global_argument,var_argument_b) if PORTA_IN==1: PORTC_OUT=PORTC_OUT^1 if x<20: PORTD_OUT=x elif 20<=x<25: #x>=20 and x<25: #both work PORTD_OUT=(2**7)+x else: PORTD_OUT=x a,b=b,a PORTD_OUT=a<<1 def wait(time): x=0 while x<100: td=0 x=x+1 while td<100: td=td+1 ss=0 while ss<time: ss=ss+1 def CPU2_main(): global PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT x=0 while 1: PORTD_OUT=PORTD_OUT^16 wait(20) if (PORTB_IN & 0x01)==1: PORTD_OUT=PORTD_OUT|0x20 else: PORTD_OUT=PORTD_OUT&0xdf #PORTD_OUT=PORTD_OUT^16 #PORTD_OUT=PORTD_OUT^16 #if (PORTA_IN & 0x01)==1: # PORTC_OUT=255 #else: # PORTC_OUT=0 ##### End of the main programm #### import MakeProcessorBytecode ProcessorCodeObject=MakeProcessorBytecode.MakeBytecode(CPU2_main,PREDEFINED_IO_ADDRESSES,globals()) #### Needed for the processor GLOBAL_FUNCTION_ADRESSES_START=ProcessorCodeObject.GLOBAL_FUNCTION_ADRESSES_START GLOBALS_MEM_CONTENT=ProcessorCodeObject.GLOBALS_MEM_CONTENT #tuple(GLOBALS_MEM_CONTENT) CONSTANTS_MEM_CONTENT=ProcessorCodeObject.CONSTANTS_MEM_CONTENT #tuple(CONSTANTS_MEM_CONTENT) COMPLETE_PROGRAMM_OPCODES=ProcessorCodeObject.COMPLETE_PROGRAMM_OPCODES #tuple(COMPLETE_PROGRAMM_OPCODES) COMPLETE_PROGRAMM_ARGS=ProcessorCodeObject.COMPLETE_PROGRAMM_ARGS #tuple(COMPLETE_PROGRAMM_ARGS) GLOBAL_OPCODE_ARG_MAX_VALUE=ProcessorCodeObject.GLOBAL_OPCODE_ARG_MAX_VALUE #max(COMPLETE_PROGRAMM_ARGS) GLOBAL_STACK_SIZE=ProcessorCodeObject.GLOBAL_STACK_SIZE ### get max stacksize ###### Start of the Processor myhdl implementation ############ from myhdl import * #import math def DP_RAM(dout, din, addr_wr,addr_rd, we, clk, WORD_SZ=8, DEPTH=16384): """ """ mem = [Signal(intbv(0,min=-2**(WORD_SZ-1),max=2**(WORD_SZ-1))) for i in range(DEPTH)] @always(clk.posedge) def write_read(): if we: mem[int(addr_wr)].next = din dout.next = mem[int(addr_rd)] #@always_comb #def read(): return write_read def RAM(clk,dout,addr,CONTENT,WORD_SZ=8): Converttosigned_sig=Signal(intbv(0,min=dout.min*2,max=dout.max*2)) @always_comb def combi_log(): Converttosigned_sig.next=CONTENT[int(addr)] #workaround to allow greater than min to max range in positive be written to port @always(clk.posedge) def rom_logic(): dout.next= Converttosigned_sig[8:].signed() #CONTENT[int(addr)] return rom_logic,combi_log def ProgrammRAM(clk,rst,Opcode,Arg1,addr,OPCODE_CONTENT,OPCODE_ARGUMENTS_CONTENT): #OPCODE_MEM=PROGRAMM_CONTENT[0] #ARG_MEM=PROGRAMM_CONTENT[0] @always(clk.posedge) def progrom_logic(): #print "address:", addr Opcode.next= OPCODE_CONTENT[int(addr)] Arg1.next= OPCODE_ARGUMENTS_CONTENT[int(addr)] return progrom_logic GLOBAL_NUMBERSTACK_OPS=22 STACK_NOP,STACK_ADD,STACK_POSITIVE,STACK_NOT,STACK_NEGATIVE,STACK_INVERT,STACK_RSHIFT,STACK_LSHIFT,STACK_AND,STACK_SUB,STACK_OR,STACK_XOR,STACK_POP,STACK_LOAD,STACK_CMP,STACK_ROT_FOUR, STACK_ROT_TWO, STACK_ROT_THREE_0,STACK_ROT_THREE_1,STACK_DUP_TOP,STACK_SETUP_LOOP,STACK_POP_BLOCK=range(GLOBAL_NUMBERSTACK_OPS) def Stack(clk,rst,TopData_Out,Data_In,StackOP,CMPmode,WORD_SZ=32,SIZE=4): CONST_LOOP_DEPTH=5 #TODO magic number if SIZE<4: SIZE=4 Stack_mem = [Signal(intbv(0,min=-2**(WORD_SZ-1),max=2**(WORD_SZ-1))) for i in range(SIZE*CONST_LOOP_DEPTH)] stack_read_addr=Signal(intbv(0,min=0,max=SIZE*CONST_LOOP_DEPTH)) stack_write_addr=Signal(intbv(0,min=0,max=SIZE*CONST_LOOP_DEPTH)) TOF_RAM_Data=Signal(intbv(0,min=-2**(WORD_SZ-1),max=2**(WORD_SZ-1))) Data_to_REG=Signal(intbv(0,min=-2**(WORD_SZ-1),max=2**(WORD_SZ-1))) #Data_to_REG_RD=Signal(intbv(0,min=-2**(WORD_SZ-1),max=2**(WORD_SZ-1))) REG_TopOfStack_Data=Signal(intbv(0,min=-2**(WORD_SZ-1),max=2**(WORD_SZ-1))) TOS_pointer=Signal(intbv(0,min=0,max=SIZE)) TOS_pointer_pre=Signal(intbv(0,min=0,max=SIZE)) #TOS3_pointer= Signal(intbv(0,min=0,max=SIZE)) REG_StackOP=Signal(intbv(0,min=0,max=GLOBAL_NUMBERSTACK_OPS)) REG_CmpMode=Signal(intbv(0,min=0,max=6)) enable_stackpointer_increase=Signal(bool(0)) enable_stackpointer_deacrease=Signal(bool(0)) enable_stack_write_data=Signal(bool(0)) stack_offset=Signal(intbv(0,min=0,max=SIZE*CONST_LOOP_DEPTH)) stack_pos_mem=[Signal(intbv(0,min=0,max=SIZE)) for i in range(CONST_LOOP_DEPTH+1)] stack_pos_mem_addr=Signal(intbv(0,min=0,max=CONST_LOOP_DEPTH+1)) SaveStack_pos=Signal(bool(0)) ReturnToStack_pos=Signal(bool(0)) #SaveStack_pos_function=Signal(bool(0)) @always(clk.posedge,rst.negedge) def seq_logic(): if rst == 0: TOS_pointer.next=0 stack_pos_mem_addr.next=0 stack_offset.next=0 REG_StackOP.next=STACK_NOP REG_CmpMode.next=0 else: if enable_stackpointer_increase: TOS_pointer.next=(TOS_pointer+1)%SIZE if enable_stackpointer_increase or enable_stack_write_data: Stack_mem[int(stack_write_addr)].next=Data_to_REG if enable_stackpointer_deacrease: TOS_pointer.next=(TOS_pointer-1)%SIZE if SaveStack_pos: #print "####### Save stack pos:",TOS_pointer stack_pos_mem[int(stack_pos_mem_addr)].next=TOS_pointer stack_pos_mem_addr.next=stack_pos_mem_addr+1 stack_offset.next=stack_offset+SIZE if ReturnToStack_pos: #print "####### Return stack pos:",TOS_pointer_pre TOS_pointer.next=TOS_pointer_pre stack_pos_mem_addr.next=stack_pos_mem_addr-1 stack_offset.next=stack_offset-SIZE TOS_pointer_pre.next=(stack_pos_mem[int(stack_pos_mem_addr-1)]) # if StackOP==STACK_LOAD: # REG_TopOfStack_Data.next=Data_In #else: REG_TopOfStack_Data.next=Data_to_REG REG_StackOP.next=StackOP REG_CmpMode.next= CMPmode TOF_RAM_Data.next=Stack_mem[int(stack_read_addr)] #@always_comb #def comb_logic2(): #TOS_Data_RD.next#=Stack_mem[int(TOS_pointer+stack_offset)] #TOS1_Data_RD.next=Stack_mem[int(TOS1_pointer+stack_offset)] #TOS2_Data_RD.next=Stack_mem[int(TOS2_pointer+stack_offset)] #TopData_Out.next=Data_to_REG #Stack_mem[int(TOS_pointer+stack_offset)] @always_comb def comb_logic(): #Data_to_REG_RD.next=REG_TopOfStack_Data stack_write_addr.next=TOS_pointer+stack_offset stack_read_addr.next=((TOS_pointer-1)%SIZE)+stack_offset #Data_to_stackmem.next=REG_TopOfStack_Data Data_to_REG.next=REG_TopOfStack_Data #TOS_Data.next=REG_TopOfStack_Data TopData_Out.next=REG_TopOfStack_Data #TopData_Out.next=0 SaveStack_pos.next=False ReturnToStack_pos.next=False enable_stackpointer_increase.next=1 enable_stackpointer_deacrease.next=0 enable_stack_write_data.next=0 if REG_StackOP==STACK_LOAD: Data_to_REG.next=Data_In TopData_Out.next=Data_In elif REG_StackOP==STACK_POP: TopData_Out.next=TOF_RAM_Data Data_to_REG.next=TOF_RAM_Data elif REG_StackOP==STACK_ADD: Data_to_REG.next=TOF_RAM_Data+REG_TopOfStack_Data TopData_Out.next=TOF_RAM_Data+REG_TopOfStack_Data elif REG_StackOP==STACK_POSITIVE: #??? Data_to_REG.next=REG_TopOfStack_Data TopData_Out.next=REG_TopOfStack_Data #TOS_Data.next=TOS_Data_RD elif REG_StackOP==STACK_NOT: Data_to_REG.next=not REG_TopOfStack_Data TopData_Out.next=not REG_TopOfStack_Data #TOS_Data.next=TOS_Data_RD elif REG_StackOP==STACK_NEGATIVE: Data_to_REG.next=-REG_TopOfStack_Data TopData_Out.next=-REG_TopOfStack_Data #TOS_Data.next=-TOS_Data_RD elif REG_StackOP==STACK_INVERT: Data_to_REG.next=~REG_TopOfStack_Data TopData_Out.next=~REG_TopOfStack_Data #TOS_Data.next=~TOS_Data_RD elif REG_StackOP==STACK_RSHIFT: Data_to_REG.next=TOF_RAM_Data>>REG_TopOfStack_Data TopData_Out.next=TOF_RAM_Data>>REG_TopOfStack_Data #TOS1_Data.next=TOS1_Data_RD>>TOS_Data_RD elif REG_StackOP==STACK_LSHIFT: Data_to_REG.next=TOF_RAM_Data<<REG_TopOfStack_Data TopData_Out.next=TOF_RAM_Data<<REG_TopOfStack_Data #TOS1_Data.next=TOS1_Data_RD<<TOS_Data_RD elif REG_StackOP==STACK_AND: Data_to_REG.next=TOF_RAM_Data®_TopOfStack_Data TopData_Out.next=TOF_RAM_Data®_TopOfStack_Data #TOS1_Data.next=TOS1_Data_RD&TOS_Data_RD elif REG_StackOP==STACK_SUB: Data_to_REG.next=TOF_RAM_Data-REG_TopOfStack_Data TopData_Out.next=TOF_RAM_Data-REG_TopOfStack_Data #TOS1_Data.next=TOS1_Data_RD-TOS_Data_RD elif REG_StackOP==STACK_OR: Data_to_REG.next=TOF_RAM_Data|REG_TopOfStack_Data TopData_Out.next=TOF_RAM_Data|REG_TopOfStack_Data elif REG_StackOP==STACK_XOR: Data_to_REG.next=TOF_RAM_Data^REG_TopOfStack_Data TopData_Out.next=TOF_RAM_Data^REG_TopOfStack_Data elif REG_StackOP==STACK_ROT_TWO: TopData_Out.next=TOF_RAM_Data Data_to_REG.next=TOF_RAM_Data elif REG_StackOP==STACK_ROT_THREE_1: TopData_Out.next=TOF_RAM_Data Data_to_REG.next=TOF_RAM_Data #elif REG_StackOP==STACK_DUP_TOP: # TopData_Out.next=REG_TopOfStack_Data #is standard assignment # Data_to_REG.next=REG_TopOfStack_Data elif REG_StackOP==STACK_POP_BLOCK: TopData_Out.next=TOF_RAM_Data Data_to_REG.next=TOF_RAM_Data elif REG_StackOP==STACK_CMP: if REG_CmpMode==0: #operator < if TOF_RAM_Data<REG_TopOfStack_Data: Data_to_REG.next=1 TopData_Out.next=1 else: Data_to_REG.next=0 TopData_Out.next=0 if REG_CmpMode==1: #operator <= if TOF_RAM_Data<=REG_TopOfStack_Data: Data_to_REG.next=1 TopData_Out.next=1 else: Data_to_REG.next=0 TopData_Out.next=0 if REG_CmpMode==2: #operator == if TOF_RAM_Data==REG_TopOfStack_Data: Data_to_REG.next=1 TopData_Out.next=1 else: Data_to_REG.next=0 TopData_Out.next=0 if REG_CmpMode==3: #operator != if TOF_RAM_Data!=REG_TopOfStack_Data: Data_to_REG.next=1 TopData_Out.next=1 else: Data_to_REG.next=0 TopData_Out.next=0 if REG_CmpMode==4: #operator > if TOF_RAM_Data>REG_TopOfStack_Data: Data_to_REG.next=1 TopData_Out.next=1 else: Data_to_REG.next=0 TopData_Out.next=0 if REG_CmpMode==5: #operator >= if TOF_RAM_Data>=REG_TopOfStack_Data: Data_to_REG.next=1 TopData_Out.next=1 else: Data_to_REG.next=0 TopData_Out.next=0 if StackOP==STACK_NOP: enable_stackpointer_increase.next=0 elif StackOP==STACK_SETUP_LOOP: enable_stackpointer_increase.next=1 SaveStack_pos.next=True elif StackOP==STACK_POP_BLOCK: stack_read_addr.next=((TOS_pointer_pre)%SIZE)+(stack_offset-SIZE) enable_stackpointer_increase.next=0 ReturnToStack_pos.next=True elif StackOP==STACK_POSITIVE: #??? enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 #TOS_Data.next=TOS_Data_RD elif StackOP==STACK_NOT: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 #TOS_Data.next=TOS_Data_RD elif StackOP==STACK_NEGATIVE: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 #TOS_Data.next=-TOS_Data_RD elif StackOP==STACK_INVERT: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 #TOS_Data.next=~TOS_Data_RD elif StackOP==STACK_ADD: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD+TOS_Data_RD elif StackOP==STACK_RSHIFT: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD>>TOS_Data_RD elif StackOP==STACK_LSHIFT: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD<<TOS_Data_RD elif StackOP==STACK_AND: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD&TOS_Data_RD elif StackOP==STACK_SUB: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD-TOS_Data_RD elif StackOP==STACK_OR: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD|TOS_Data_RD elif StackOP==STACK_XOR: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD^TOS_Data_RD elif StackOP==STACK_POP: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 # elif StackOP==STACK_CALL_FUNCTION: # enable_stackpointer_increase.next=0 # enable_stackpointer_deacrease.next=1 #pop function address # SaveStack_pos_function.next=True elif StackOP==STACK_LOAD: enable_stackpointer_increase.next=1 enable_stackpointer_deacrease.next=0 #TopOfStack_Data.next=Data_In elif StackOP==STACK_ROT_TWO: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 enable_stack_write_data.next=1 stack_write_addr.next=((TOS_pointer-1)%SIZE)+stack_offset #TOS_Data.next=TOS1_Data_RD #TOS1_Data.next=TOS_Data_RD elif StackOP==STACK_ROT_THREE_0: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 enable_stack_write_data.next=1 stack_write_addr.next=((TOS_pointer-2)%SIZE)+stack_offset stack_read_addr.next=((TOS_pointer-2)%SIZE)+stack_offset elif StackOP==STACK_ROT_THREE_1: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 enable_stack_write_data.next=1 Data_to_REG.next=TOF_RAM_Data stack_write_addr.next=((TOS_pointer-1)%SIZE)+stack_offset stack_read_addr.next=((TOS_pointer-1)%SIZE)+stack_offset #TOS_Data.next=TOS1_Data_RD #TOS1_Data.next=TOS2_Data_RD #TOS2_Data.next=TOS_Data_RD #elif StackOP==STACK_ROT_FOUR: ##TODO #TOS_Data.next=Stack_mem[int(TOS_pointer)] # TOS1_Data.next=Stack_mem[int(TOS1_pointer)] # TOS2_Data.next=Stack_mem[int(TOS2_pointer)] elif StackOP==STACK_DUP_TOP: enable_stackpointer_increase.next=1 enable_stackpointer_deacrease.next=0 elif StackOP==STACK_CMP: enable_stackpointer_increase.next=1 enable_stackpointer_deacrease.next=0 else: enable_stackpointer_increase.next=0 return seq_logic,comb_logic#,comb_logic2 def IOModule(clk,rst,dout,din,addr,we,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,GLOBAL_CONTENT,WIDTH=32): Sync_in1_PORTA=Signal(intbv(0)[WIDTH:]) Sync_in2_PORTA=Signal(intbv(0)[WIDTH:]) Sync_in1_PORTB=Signal(intbv(0)[WIDTH:]) Sync_in2_PORTB=Signal(intbv(0)[WIDTH:]) INTERN_PORTC_OUT=Signal(intbv(0)[WIDTH:]) INTERN_PORTD_OUT=Signal(intbv(0)[WIDTH:]) glob_mem = [Signal(intbv(0,min=-2**(WIDTH-1),max=2**(WIDTH-1))) for i in range(len(GLOBAL_CONTENT))] @always(clk.posedge,rst.negedge) def IO_write_sync(): if rst==0: INTERN_PORTC_OUT.next=0 INTERN_PORTD_OUT.next=0 for i in range(len(GLOBAL_CONTENT)): glob_mem[int(i)].next=GLOBAL_CONTENT[i] ##TODO this must be a memory initialisation else: Sync_in1_PORTA.next=PORTA_IN Sync_in2_PORTA.next=Sync_in1_PORTA Sync_in1_PORTB.next=PORTB_IN Sync_in2_PORTB.next=Sync_in1_PORTB if we: if addr==2: INTERN_PORTC_OUT.next=din[WIDTH:] elif addr==3: INTERN_PORTD_OUT.next=din[WIDTH:] elif addr>=4: glob_mem[int(addr-4)].next=din #GLOBAL_CONTENT[int(addr-4)] @always(clk.posedge) def IO_read(): PORTC_OUT.next=INTERN_PORTC_OUT PORTD_OUT.next=INTERN_PORTD_OUT dout.next = 0 if addr==0: dout.next = Sync_in2_PORTA[WIDTH:].signed() if addr==1: dout.next = Sync_in2_PORTB[WIDTH:].signed() if addr==2: dout.next = INTERN_PORTC_OUT[WIDTH:].signed() if addr==3: dout.next = INTERN_PORTD_OUT[WIDTH:].signed() if addr>=4: dout.next =glob_mem[int(addr-4)] return IO_write_sync,IO_read def Processor(clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,CPU_PROGRAM_OPCODES=COMPLETE_PROGRAMM_OPCODES,CPU_PROGRAM_ARGS=COMPLETE_PROGRAMM_ARGS,CPU_CONSTANTS=CONSTANTS_MEM_CONTENT,CPU_GLOBALS=GLOBALS_MEM_CONTENT,CONST_FUNCTION_ADRESSES_START=GLOBAL_FUNCTION_ADRESSES_START,VAR_BITWIDTH=32,VAR_MEM_DEPTH=20,STACK_SIZE=GLOBAL_STACK_SIZE,OPCODE_ARG_MAX_VALUE=GLOBAL_OPCODE_ARG_MAX_VALUE,DEBUG_OUTPUT=False): CONST_PROGRAMM_LENGTH=len(CPU_PROGRAM_OPCODES) NUMBER_OF_SELECTS=4 ENUM_SEL_NONE,ENUM_SEL_VARIABLE,ENUM_SEL_CONST,ENUM_SEL_GLOBAL=range(NUMBER_OF_SELECTS) StackTopSel=Signal(intbv(0,min=0,max=NUMBER_OF_SELECTS)) REG_StackTopSel=Signal(intbv(0,min=0,max=NUMBER_OF_SELECTS)) NUMBER_FROM_SELECTS=4 FROM_NONE,FROM_CONST,FROM_GLOBAL,FROM_VAR=range(NUMBER_FROM_SELECTS) argnext_store=Signal(intbv(0,min=0,max=NUMBER_FROM_SELECTS)) REG_argnext_store=Signal(intbv(0,min=0,max=NUMBER_FROM_SELECTS)) #### helping signals MAX_NUMBER_FUNCTION_ARGUMENTS=10 #TODO magic number #EnableJump=Signal(bool(0)) Inc_ArgumentCount=Signal(bool(0)) Clear_ArgumentCount=Signal(bool(0)) REG_ArgumentCount=Signal(intbv(0,min=0,max=MAX_NUMBER_FUNCTION_ARGUMENTS+2)) JumpValue=Signal(intbv(0)[8:]) MAX_SUB_CYCLES=2 REG_sub_pc_count=Signal(intbv(0,min=0,max=MAX_SUB_CYCLES)) sub_pc_count_next=Signal(intbv(0,min=0,max=MAX_SUB_CYCLES)) Push_Programcounter=Signal(bool(0)) Pop_Programcounter=Signal(bool(0)) Old_ProgrammCounter=Signal(intbv(0,min=0,max=CONST_PROGRAMM_LENGTH+1)) REG_PC_offsetValue=Signal(intbv(0,min=0,max=CONST_PROGRAMM_LENGTH+1)) PC_offsetValue=Signal(intbv(0,min=0,max=CONST_PROGRAMM_LENGTH+1)) Old_PC_offsetValue=Signal(intbv(0,min=0,max=CONST_PROGRAMM_LENGTH+1)) Set_Variables_offset=Signal(bool(0)) #Return_Variables_offset=Signal(bool(0)) #### Programm Memory Signals Opcode=Signal(intbv(0)[8:]) Arg1=Signal(intbv(0,min=0,max=OPCODE_ARG_MAX_VALUE+1)) REG_ProgramCounter=Signal(intbv(-1,min=-1,max=CONST_PROGRAMM_LENGTH+1)) #### Constants Memory Signals ConstantsData=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) ConstantsAddr=Signal(intbv(0,min=0,max=len(CPU_CONSTANTS))) #### Programm Variables RAM Signals Varibles_DataOut=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) #Signal(intbv(0)[VAR_BITWIDTH:]) Variables_DataIn=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) #Signal(intbv(0)[VAR_BITWIDTH:]) VariablesAddr=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) VariablesAddr_write_to_inst=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) VariablesAddr_read_to_inst=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) REG_max_Variables_address=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) Old_max_Variables_address=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) REG_Variables_addr_offset=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) Old_Variables_addr_offset=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) Variables_we=Signal(bool(0)) #### Stack Signals # STACK_SIZE Stack_DataIn=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) #Signal(intbv(0)[VAR_BITWIDTH:]) StackValue0=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) #Signal(intbv(0)[VAR_BITWIDTH:]) StackOP=Signal(intbv(0,min=0,max=GLOBAL_NUMBERSTACK_OPS)) StackOP_CMPmode=Signal(intbv(0,min=0,max=6)) #### IO Module Signals NR_IO_ADDRESSES=4 # TODO magic number IO_MODULE_LENGTH_MAX=NR_IO_ADDRESSES+len(GLOBALS_MEM_CONTENT)+1 CONST_FUNCTION_ADRESSES_START # <-- is a parameter of the processor unit IO_DataOut=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) #Signal(intbv(0)[VAR_BITWIDTH:]) IO_DataIn=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) #Signal(intbv(0)[VAR_BITWIDTH:]) IO_addr=Signal(intbv(0,min=0,max=IO_MODULE_LENGTH_MAX)) IO_we=Signal(bool(0)) ####Variables RAM instantiation VariablesRAM_inst=DP_RAM(Varibles_DataOut, Variables_DataIn, VariablesAddr_write_to_inst,VariablesAddr_read_to_inst, Variables_we, clk, WORD_SZ=VAR_BITWIDTH, DEPTH=VAR_MEM_DEPTH) ###Programm Code Memory instantiation ProgrammCode_inst=ProgrammRAM(clk,rst,Opcode,Arg1,JumpValue,OPCODE_CONTENT=CPU_PROGRAM_OPCODES,OPCODE_ARGUMENTS_CONTENT=CPU_PROGRAM_ARGS) ###Constants memory instantiation ConstantsRAM_inst=RAM(clk,ConstantsData,ConstantsAddr,CPU_CONSTANTS,WORD_SZ=VAR_BITWIDTH) ###The stack TheStack_inst=Stack(clk,rst,StackValue0,Stack_DataIn,StackOP,StackOP_CMPmode, WORD_SZ=VAR_BITWIDTH,SIZE=STACK_SIZE) ###I/O Module instantiation IOModule_inst=IOModule(clk,rst,IO_DataOut,IO_DataIn,IO_addr,IO_we,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,GLOBAL_CONTENT=CPU_GLOBALS,WIDTH=VAR_BITWIDTH) CONST_PC_STACK_DEPTH=5 #Defines how many nasted function are possible TODO magic number REG_pc_stack_addr=Signal(intbv(0,min=0,max=CONST_PC_STACK_DEPTH)) pc_steck_mem = [Signal(intbv(0,min=0,max=CONST_PROGRAMM_LENGTH+1)) for i in range(CONST_PC_STACK_DEPTH)] pc_offsets_mem = [Signal(intbv(0,min=0,max=CONST_PROGRAMM_LENGTH+1)) for i in range(CONST_PC_STACK_DEPTH)] max_var_addr_mem=[Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) for i in range(CONST_PC_STACK_DEPTH)] @always(clk.posedge,rst.negedge) def seq_logic(): if rst == 0: ##### REG_ProgramCounter Part ######## REG_ProgramCounter.next = -1 #TODO very not nice ##### END REG_ProgramCounter Part ######## REG_ArgumentCount.next=0 REG_max_Variables_address.next=0 REG_Variables_addr_offset.next=0 REG_pc_stack_addr.next=0 REG_PC_offsetValue.next=0 REG_StackTopSel.next=ENUM_SEL_NONE REG_sub_pc_count.next=0 else: if Inc_ArgumentCount==True: REG_ArgumentCount.next=REG_ArgumentCount+1 if Clear_ArgumentCount==True: REG_ArgumentCount.next=0 if VariablesAddr_write_to_inst>=REG_max_Variables_address: REG_max_Variables_address.next=VariablesAddr_write_to_inst+1 #print "REG_max_Variables_address",REG_max_Variables_address REG_StackTopSel.next=StackTopSel REG_argnext_store.next=argnext_store ##### REG_ProgramCounter Part ######## #if EnableJump==True: REG_ProgramCounter.next=JumpValue #else: # REG_ProgramCounter.next = REG_ProgramCounter+1 REG_PC_offsetValue.next=PC_offsetValue ##### END REG_ProgramCounter Part ######## REG_sub_pc_count.next=sub_pc_count_next ##### Programmm counter stack####### if Push_Programcounter: # Set at CALL_FUNCTION pc_steck_mem[int(REG_pc_stack_addr-1)].next=REG_ProgramCounter pc_offsets_mem[int(REG_pc_stack_addr-1)].next=REG_PC_offsetValue if Pop_Programcounter: # Set at RETURN_VALUE REG_pc_stack_addr.next=REG_pc_stack_addr-1 REG_Variables_addr_offset.next=Old_Variables_addr_offset REG_max_Variables_address.next=Old_max_Variables_address #print "########returning REG_max_Variables_address:", REG_max_Variables_address,Old_max_Variables_address,Old_Variables_addr_offset #####End Programmm counter stack######### if Set_Variables_offset: # Set at LOAD_GLOBAL if a function address is loaded REG_pc_stack_addr.next=REG_pc_stack_addr+1 max_var_addr_mem[int(REG_pc_stack_addr)].next=REG_max_Variables_address REG_Variables_addr_offset.next=REG_max_Variables_address #print "###########LOAD_GLOBAL",REG_Variables_addr_offset, REG_max_Variables_address,REG_ProgramCounter,JumpValue #if Return_Variables_offset: @always_comb def comb_logic2(): VariablesAddr_write_to_inst.next=REG_Variables_addr_offset+VariablesAddr #print "VariablesAddr",VariablesAddr, "REG_Variables_addr_offset",REG_Variables_addr_offset Old_ProgrammCounter.next=0 Old_max_Variables_address.next=0 Old_Variables_addr_offset.next=0 Old_PC_offsetValue.next=0 if REG_pc_stack_addr>0: Old_PC_offsetValue.next=pc_offsets_mem[int(REG_pc_stack_addr-1)] Old_ProgrammCounter.next=pc_steck_mem[int(REG_pc_stack_addr-1)] Old_max_Variables_address.next=max_var_addr_mem[int(REG_pc_stack_addr-1)] if REG_pc_stack_addr>1: Old_Variables_addr_offset.next=max_var_addr_mem[int(REG_pc_stack_addr-2)] ##### Opcode handling############# @always_comb def comb_logic(): sub_pc_count_next.next=0 VariablesAddr_read_to_inst.next=VariablesAddr_write_to_inst #Enable_PC_offset.next=False PC_offsetValue.next=REG_PC_offsetValue Set_Variables_offset.next=False #Return_Variables_offset.next=False Push_Programcounter.next=False Pop_Programcounter.next=False Inc_ArgumentCount.next=False Clear_ArgumentCount.next=False #EnableJump.next=False JumpValue.next=REG_ProgramCounter+1 ConstantsAddr.next=0 StackOP.next=STACK_NOP StackOP_CMPmode.next=0 Stack_DataIn.next=0 Variables_we.next=False VariablesAddr.next=0 Variables_DataIn.next=StackValue0 IO_we.next=False IO_addr.next=0 IO_DataIn.next=StackValue0 StackTopSel.next=ENUM_SEL_NONE if REG_StackTopSel==ENUM_SEL_CONST: Stack_DataIn.next=ConstantsData elif REG_StackTopSel==ENUM_SEL_GLOBAL: Stack_DataIn.next=IO_DataOut elif REG_StackTopSel==ENUM_SEL_VARIABLE: Stack_DataIn.next=Varibles_DataOut elif REG_StackTopSel==ENUM_SEL_NONE: Stack_DataIn.next=0 argnext_store.next=FROM_NONE if REG_argnext_store==FROM_GLOBAL: VariablesAddr.next=REG_ArgumentCount-2 Variables_DataIn.next=IO_DataOut Variables_we.next=True elif REG_argnext_store==FROM_VAR: VariablesAddr.next=REG_ArgumentCount-2 Variables_DataIn.next=Varibles_DataOut Variables_we.next=True elif REG_argnext_store==FROM_CONST: VariablesAddr.next=REG_ArgumentCount-2 Variables_DataIn.next=ConstantsData Variables_we.next=True if Opcode==23: #dis.opmap['BINARY_ADD']: # 23, StackOP.next=STACK_ADD elif Opcode==64: #dis.opmap['BINARY_AND']: # 64, StackOP.next=STACK_ADD elif Opcode==62: #dis.opmap['BINARY_LSHIFT']: #: 62, StackOP.next=STACK_LSHIFT elif Opcode==66: #dis.opmap['BINARY_OR']: #: 66, StackOP.next=STACK_OR elif Opcode==63: #dis.opmap['BINARY_RSHIFT']: #: 63, StackOP.next=STACK_RSHIFT elif Opcode==24: #dis.opmap['BINARY_SUBTRACT']: #: 24, StackOP.next=STACK_SUB elif Opcode==65: #dis.opmap['BINARY_XOR']: #: 65, StackOP.next=STACK_XOR elif Opcode==107: #dis.opmap['COMPARE_OP']: #: 107, StackOP.next=STACK_CMP StackOP_CMPmode.next=Arg1 elif Opcode==4: #dis.opmap[''DUP_TOP']: # 4 StackOP.next=STACK_DUP_TOP elif Opcode==113: #dis.opmap['JUMP_ABSOLUTE'] : #: 113, #EnableJump.next=True JumpValue.next=Arg1+REG_PC_offsetValue elif Opcode==110: #dis.opmap['JUMP_FORWARD']: #: 110, #EnableJump.next=True #print "JUMP_FORWARD" JumpValue.next=REG_ProgramCounter+1+Arg1 #relative jump elif Opcode==111: #dis.opmap['JUMP_IF_FALSE_OR_POP']: #: 111, if StackValue0[1:0]==0: #EnableJump.next=True JumpValue.next=Arg1+REG_PC_offsetValue else: StackOP.next=STACK_POP elif Opcode==112: #dis.opmap['JUMP_IF_TRUE_OR_POP']: #: 112, if StackValue0[1:0]==1: JumpValue.next=Arg1+REG_PC_offsetValue #EnableJump.next=True else: StackOP.next=STACK_POP elif Opcode==100: #dis.opmap['LOAD_CONST']: #: 100, if REG_ArgumentCount==0: StackOP.next=STACK_LOAD StackTopSel.next=ENUM_SEL_CONST ConstantsAddr.next=Arg1 else: Inc_ArgumentCount.next=True ConstantsAddr.next=Arg1 argnext_store.next=FROM_CONST elif Opcode==124: #dis.opmap['LOAD_FAST']: #: 124, #TODO Split read and write address to support var arguments if REG_ArgumentCount==0: StackOP.next=STACK_LOAD VariablesAddr.next=Arg1 StackTopSel.next=ENUM_SEL_VARIABLE else: Inc_ArgumentCount.next=True VariablesAddr_read_to_inst.next=Old_Variables_addr_offset+Arg1 argnext_store.next=FROM_VAR elif Opcode==116: #dis.opmap['LOAD_GLOBAL']: #116, if Arg1>=CONST_FUNCTION_ADRESSES_START: Inc_ArgumentCount.next=True Set_Variables_offset.next=True if REG_ArgumentCount==0: # load from global mem StackOP.next=STACK_LOAD IO_addr.next=Arg1 StackTopSel.next=ENUM_SEL_GLOBAL else: Inc_ArgumentCount.next=True IO_addr.next=Arg1 argnext_store.next=FROM_GLOBAL elif Opcode==131: #dis.opmap['CALL_FUNCTION'] #print "############### Call Function ##########" Push_Programcounter.next=True #Enable_PC_offset.next=True JumpValue.next=StackValue0 PC_offsetValue.next=StackValue0 #Put on the stack with LOAD_GLOBAL StackOP.next=STACK_POP # The Function Arguments are not loaded over the stack # they are written directly to the Variables RAM if the LOAD_GLOBAL argument is in the Function address range Clear_ArgumentCount.next=True elif Opcode==83: #dis.opmap['RETURN_VALUE'] #print "############### Return Function ##########" #Enable_PC_offset.next=True PC_offsetValue.next=Old_PC_offsetValue JumpValue.next=Old_ProgrammCounter+1 Pop_Programcounter.next=True #StackOP.next=STACK_POP_BLOCK elif Opcode==97: #dis.opmap['STORE_GLOBAL']: 97, IO_we.next=True IO_addr.next=Arg1 StackOP.next=STACK_POP elif Opcode==114: #dis.opmap['POP_JUMP_IF_FALSE']: #: 114, StackOP.next=STACK_POP if StackValue0[1:0]==0: JumpValue.next=Arg1+REG_PC_offsetValue #EnableJump.next=True elif Opcode==115: #dis.opmap['POP_JUMP_IF_TRUE']: #: 115, StackOP.next=STACK_POP if StackValue0[1:0]==1: JumpValue.next=Arg1+REG_PC_offsetValue #EnableJump.next=True elif Opcode==1: #dis.opmap['POP_TOP'] StackOP.next=STACK_POP elif Opcode==5: #dis.opmap['ROT_FOUR']: #: 5, StackOP.next=STACK_ROT_FOUR elif Opcode==3: #dis.opmap['ROT_THREE']: #: 3, if REG_sub_pc_count==0: sub_pc_count_next.next=REG_sub_pc_count+1 JumpValue.next=REG_ProgramCounter StackOP.next=STACK_ROT_THREE_0 if REG_sub_pc_count==1: sub_pc_count_next.next=0 StackOP.next=STACK_ROT_THREE_1 elif Opcode==2: #dis.opmap['ROT_TWO']: #: 2, StackOP.next=STACK_ROT_TWO elif Opcode==125: #dis.opmap['STORE_FAST']: #: 125, Variables_we.next=True VariablesAddr.next=Arg1 StackOP.next=STACK_POP elif Opcode==15: #dis.opmap['UNARY_INVERT']: #:15 StackOP.next=STACK_INVERT elif Opcode==11: #dis.opmap['UNARY_NEGATIVE']: #: 11, StackOP.next=STACK_NEGATIVE elif Opcode==12: #dis.opmap['UNARY_NOT']: #: 12, StackOP.next=STACK_NOT elif Opcode==10: #dis.opmap['UNARY_POSITIVE']: #: 10, StackOP.next=STACK_POSITIVE elif Opcode==120: #dis.opmap['SETUP_LOOP']: # TODO?? #(explanation from python homepage) Pushes a block for a loop onto the block stack. The block spans from the current instruction with a size of delta bytes. StackOP.next=STACK_SETUP_LOOP #print "##########setup loop" elif Opcode==87: #dis.opmap['POP_BLOCK']: # TODO?? dis.opmap['POP_BLOCK'] StackOP.next=STACK_POP_BLOCK #print "##########pop block" else: StackOP.next=STACK_NOP #raise ValueError("Unsuported Command:"+str(Opcode)) #if rst!=0: print "Comand not supported:",Opcode if DEBUG_OUTPUT: import dis cmp_op = dis.cmp_op hasconst = dis.hasconst hasname = dis.hasname hasjrel = dis.hasjrel haslocal = dis.haslocal hascompare = dis.hascompare @always(Opcode,Arg1) def monitor_opcode(): instruction = (dis.opname[int(Opcode)]+" "+str(int(Opcode)), None, None, None) if Opcode in hasconst: instruction = (instruction[0],int(Arg1) ,'const=', CPU_CONSTANTS[Arg1]) elif Opcode in hasname: #if Arg1>NR_IO_ADDRESSES: # instruction = (instruction[0],Arg1 ,'global=', CPU_GLOBALS[Arg1]) #else: instruction = (instruction[0],int(Arg1) ,None, None) #print "Error: no name instruction is supported yet" #raise StopSimulation elif Opcode in hasjrel: instruction = (instruction[0], int(Arg1),'addr=', REG_ProgramCounter+Arg1) elif Opcode in haslocal: instruction = (instruction[0], int(Arg1),'var=', int(Varibles_DataOut.val)) elif Opcode in hascompare: instruction = (instruction[0], int(Arg1),'cmp=', cmp_op[Arg1]) print instruction if DEBUG_OUTPUT: return seq_logic,comb_logic,comb_logic2,VariablesRAM_inst,ProgrammCode_inst,ConstantsRAM_inst,TheStack_inst,IOModule_inst,monitor_opcode else: return seq_logic,comb_logic,comb_logic2,VariablesRAM_inst,ProgrammCode_inst,ConstantsRAM_inst,TheStack_inst,IOModule_inst #,monitor_opcode def Processor_TESTBENCH(): WORD_SZ=8 rst, clk = [Signal(bool(0)) for i in range(2)] PORTA_IN=Signal(intbv(0)[WORD_SZ:]) PORTB_IN=Signal(intbv(0)[WORD_SZ:]) PORTC_OUT=Signal(intbv(0)[WORD_SZ:]) PORTD_OUT=Signal(intbv(0)[WORD_SZ:]) toVHDL(Processor,clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,VAR_BITWIDTH=WORD_SZ) Processor_inst=Processor(clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,VAR_BITWIDTH=WORD_SZ,DEBUG_OUTPUT=False) @always(delay(10)) def clkgen(): clk.next = not clk @instance def stimulus(): print "Reseting ########" rst.next=0 print "Setting PORTA_IN too 0 ########" PORTA_IN.next=0 for i in range(3): yield clk.negedge print "Release Reset ########" rst.next=1 for i in range(200): yield clk.negedge print "Setting PORTA_IN too 1 (PORTC bit 0 should toggle) ########" PORTA_IN.next=1 for i in range(2000): yield clk.negedge print "Setting PORTA_IN too 0 (PORTC bit 0 should stop toggling) ########" PORTA_IN.next=0 for i in range(2000): yield clk.negedge raise StopSimulation @instance def Monitor_PORTC(): print "\t\tPortC:",PORTC_OUT,"Binary:" ,bin(PORTC_OUT,WORD_SZ) ##TODO bin is not supported in simulation while 1: yield PORTC_OUT print "\t\tPortC:",PORTC_OUT,"Binary:" ,bin(PORTC_OUT,WORD_SZ) @instance def Monitor_PORTD(): print "PortD:",PORTD_OUT while 1: yield PORTD_OUT print "PortD:",PORTD_OUT return clkgen,Processor_inst,stimulus,Monitor_PORTC,Monitor_PORTD def ClkSysClk(clk_intern): @always(clk_intern) def logic(): # do nothing here pass clk_intern.driven="wire" __vhdl__="""OSCInst0: OSCH -- synthesis translate_off GENERIC MAP ( NOM_FREQ => "2.08" ) -- synthesis translate_on PORT MAP ( STDBY=> '0', OSC=> %(clk_intern)s);""" return logic def PicoBoard(iPushBn,rst, iCap_btn1,iCap_btn2,iCap_btn3,iCap_btn4, oLCD_COM0,oLCD_COM1,oLCD_COM2,oLCD_COM3,oLCD_5,oLCD_6,oLCD_7,oLCD_8,oLCD_9,oLCD_10,oLCD_11,oLCD_12, iUart_rx,oUart_tx, oSpi_sclk,oSpi_csn,oSpi_mosi,iSpi_miso, ioScl,ioSda, oI2CAlert,oEnAMP,oEnTempSPI, Icc_analog_cmp_n,iIcc_analog_cmp_p,oIcc_analog_out,iIcco_analog_cmp_n,iIcco_analog_cmp_p,oIcco_analog_out, iClk_USB,oUSBorBattout,oTouched1out): WORD_SZ=8 #rst, clk = [Signal(bool(0)) for i in range(2)] clk_intern=Signal(bool(0)) btn_rst=Signal(bool(0)) #nRst=Signal(bool(0)) PORTA_IN=Signal(intbv(0)[WORD_SZ:]) PORTB_IN=Signal(intbv(0)[WORD_SZ:]) PORTC_OUT=Signal(intbv(0)[WORD_SZ:]) PORTD_OUT=Signal(intbv(0)[WORD_SZ:]) #counter=Signal(intbv(0,min=0,max=12000000)) #tog=Signal(bool(0)) Processor_inst=Processor(iClk_USB,btn_rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,VAR_BITWIDTH=WORD_SZ,DEBUG_OUTPUT=False) #@always(iClk_USB.posedge) #def seqen_logic(): # counter.next=(counter+1)%12000000 # if counter==0: # tog.next=not tog # oUSBorBattout.next=tog # Clk_inst=ClkSysClk(clk_intern) #connect processor to outside world @always_comb def combo_logic(): PORTB_IN[0].next=iCap_btn1 PORTB_IN[1].next=iCap_btn2 PORTB_IN[3].next=iCap_btn3 PORTB_IN[4].next=iCap_btn4 #PORTA_IN[0].next=iPushBn btn_rst.next=iPushBn oLCD_5.next=PORTC_OUT[0] oLCD_6.next=PORTC_OUT[1] oLCD_7.next=PORTC_OUT[2] oLCD_8.next=PORTC_OUT[3] oLCD_9.next=PORTC_OUT[4] oLCD_10.next=PORTC_OUT[5] oLCD_11.next=PORTC_OUT[6] oLCD_12.next=PORTC_OUT[7] oLCD_COM0.next=PORTD_OUT[0] oLCD_COM1.next=PORTD_OUT[1] oLCD_COM2.next=PORTD_OUT[2] oLCD_COM3.next=PORTD_OUT[3] oUart_tx.next=0 oSpi_sclk.next=0 oSpi_csn.next=0 oSpi_mosi.next=0 ioScl.next=0 ioSda.next=0 oI2CAlert.next=0 oEnAMP.next=0 oEnTempSPI.next=0 oIcc_analog_out.next=0 oIcco_analog_out.next=0 oTouched1out.next=PORTD_OUT[4] oUSBorBattout.next=PORTD_OUT[5] return Processor_inst,combo_logic#,seqen_logic #,Clk_inst ##################### convert pico Board to VHDL################### NumberArguments=38 for i in range(NumberArguments): code="A"+str(i)+"= Signal(bool(0))" exec(code) code="toVHDL(PicoBoard" for i in range(NumberArguments): code=code+",A"+str(i) code=code+")" exec(code) ##################### convert pico Board to VHDL################### #toVHDL(Processor,clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,VAR_BITWIDTH=WORD_SZ) #toVHDL(Processor_TESTBENCH) #tb = traceSignals(Processor_TESTBENCH) sim = Simulation(Processor_TESTBENCH()) #sim = Simulation(tb) sim.run() #def convert(): # WORD_SZ=8 # DEPTH=16384 # we, clk = [Signal(bool(0)) for i in range(2)] # dout = Signal(intbv(0)[WORD_SZ:]) # din = Signal(intbv(0)[WORD_SZ:]) # addr = Signal(intbv(0)[16:]) # toVHDL(RAM, dout, din, addr, we,clk,WORD_SZ,DEPTH) #convert() #def simulate(timesteps): # tb = traceSignals(test_dffa) # sim = Simulation(tb) # sim.run(timesteps) #simulate(20000) And the MakeProcessorBytecode Module: import dis ################# Reworking the bytecode, so that it better fits into the Processor (e.g Alignment issues)################### class MakeBytecode: def __init__(self,mainfunction,PredefinedIOAddresses,OtherGlobals): for Portname in PredefinedIOAddresses.keys(): OtherGlobals[Portname]=0 Unworked_functionArray={mainfunction.func_name:mainfunction} occuring_globals_dict=PredefinedIOAddresses Processed_functions_dict={} function_names_inorder=[] Function_offset=0 programm_dict={} while len(Unworked_functionArray)>0: funcname,currentfunction=Unworked_functionArray.popitem() Processed_functions_dict[funcname]=(Function_offset,currentfunction) #create function mapping in Programm Rom (start addresses of functions) function_names_inorder.append(funcname) theprogramm=tuple([ord(i) for i in currentfunction.func_code.co_code]) # count=0 new_count=0 REWORKED_GLOBAL_PROGRAMM_OPCODE=[] REWORKED_GLOBAL_PROGRAMM_ARG=[] Addressmap_old_new={} # create a seperate opcode and argument List (fits better in myhdl ram) # extend opcodes without argument with an 0 argument while 1: if count<len(theprogramm): REWORKED_GLOBAL_PROGRAMM_OPCODE.append(theprogramm[count]) Addressmap_old_new[count]=new_count if theprogramm[count]>=dis.HAVE_ARGUMENT: actual_Argument=(theprogramm[count+2]<<8)+theprogramm[count+1] REWORKED_GLOBAL_PROGRAMM_ARG.append(actual_Argument) if theprogramm[count]==dis.opmap['LOAD_GLOBAL']: if hasattr(OtherGlobals[currentfunction.func_code.co_names[actual_Argument]], '__call__'): # if GLOBAL_LOAD loads a function if not Processed_functions_dict.has_key(currentfunction.func_code.co_names[actual_Argument]): #if function is allready processed ##every function is just added once because it is a dictionary Unworked_functionArray[currentfunction.func_code.co_names[actual_Argument]]=OtherGlobals[currentfunction.func_code.co_names[actual_Argument]] count=count+3 else: REWORKED_GLOBAL_PROGRAMM_ARG.append(0) count=count+1 new_count=new_count+1 else: break Function_offset=Function_offset+len(REWORKED_GLOBAL_PROGRAMM_OPCODE) # next function will get next free Programm ROM Address # Readjust all absolute jump addresses for index,i in enumerate(REWORKED_GLOBAL_PROGRAMM_OPCODE): if i in dis.hasjabs: REWORKED_GLOBAL_PROGRAMM_ARG[index]=Addressmap_old_new[REWORKED_GLOBAL_PROGRAMM_ARG[index]] # Readjust relative jump addresses, for now only JUMP_FORWARD is changed count=0 while 1: if count<len(theprogramm): if theprogramm[count]>=dis.HAVE_ARGUMENT: actual_Argument=(theprogramm[count+2]<<8)+theprogramm[count+1] if theprogramm[count]==dis.opmap['JUMP_FORWARD']: #print count REWORKED_GLOBAL_PROGRAMM_ARG[Addressmap_old_new[count]]=Addressmap_old_new[count+3+actual_Argument]-Addressmap_old_new[count+3] count=count+3 else: count=count+1 else: break programm_dict[funcname]=(REWORKED_GLOBAL_PROGRAMM_OPCODE,REWORKED_GLOBAL_PROGRAMM_ARG) ## after this: Every Opcode and argument is at one address, Absolut jumps are corrected, and relative JUMP_FORWARD is corrected ########## end while len(Unworked_functionArray)>0: ######### #occuring_globals_dict=PREDEFINED_IO_ADDRESSES self.GLOBALS_MEM_CONTENT=[] if len(occuring_globals_dict)>0: globals_addr=max(occuring_globals_dict.values())+1 else: globals_addr=0 occuring_const_values_dict={} self.CONSTANTS_MEM_CONTENT=[] if len(occuring_const_values_dict)>0: const_addr=max(occuring_const_values_dict.values())+1 else: const_addr=0 ### Adjust and merge LOAD_GLOBAL, STORE_GLOBAL,LOAD_CONST , and Global_mem ##create shared GLOBALS_MEM_CONTENT and shared CONSTANTS_MEM_CONTENT ###merge constants (because python creates uniqe constants for every function) ###merge globals (introduce global_var_mem, only for function calling and global constants) ###rework global addresses (LOAD_GLOBAL, STORE_GLOBAL) ###rework const addresses (LOAD_CONST) ###rework absolut jump addresses of functions (LOAD_GLOBAL) ###only constant arguments are supported, or dual ported var mem is needed list_Load_global_when_fcall=[] for funcname in function_names_inorder: currentprogramm_opcodes=programm_dict[funcname][0] currentprogramm_arg=programm_dict[funcname][1] for index,i in enumerate(currentprogramm_opcodes): if i==dis.opmap['LOAD_CONST']: const_value=Processed_functions_dict[funcname][1].func_code.co_consts[currentprogramm_arg[index]] if type(const_value)==type(0): if not occuring_const_values_dict.has_key(const_value): self.CONSTANTS_MEM_CONTENT.append(const_value) occuring_const_values_dict[const_value]=const_addr const_addr=const_addr+1 currentprogramm_arg[index]=occuring_const_values_dict[const_value] elif type(const_value)==type(None) and currentprogramm_arg[index]==0: pass else: print "Error: Only integers are suportted, Type is:",type(const_value) if i==dis.opmap['LOAD_GLOBAL'] or i==dis.opmap['STORE_GLOBAL']: global_name=Processed_functions_dict[funcname][1].func_code.co_names[currentprogramm_arg[index]] if type(OtherGlobals[global_name])==type(0): ##needs to be an integer if not occuring_globals_dict.has_key(global_name): occuring_globals_dict[global_name]=globals_addr self.GLOBALS_MEM_CONTENT.append(OtherGlobals[global_name]) globals_addr=globals_addr+1 currentprogramm_arg[index]=occuring_globals_dict[global_name] elif i==dis.opmap['LOAD_GLOBAL'] and hasattr(OtherGlobals[global_name], '__call__'): list_Load_global_when_fcall.append((funcname,global_name,index)) else: print "Error: Only integers are suportted, Type is:",type(OtherGlobals[global_name]) #store changes programm_dict[funcname]=(currentprogramm_opcodes,currentprogramm_arg) #print occuring_globals_dict #print "ops:",currentprogramm_opcodes #print "args:",currentprogramm_arg self.GLOBAL_FUNCTION_ADRESSES_START=globals_addr ##### rework LOAD_GLOBAL arguments when functions are loaded and add the function address to the GLOBALS_MEM_CONTENT ##### functions addresses are the highest addresses in the GLOBAL_MEM,GLOBAL_FUNCTION_ADRESSES_START is used in the core ##### to decide wheter it is a normal LOAD_GLOBAL or if the LOAD global loads a function for basefuncname,callfunctionname,index in list_Load_global_when_fcall: if not occuring_globals_dict.has_key(callfunctionname): occuring_globals_dict[callfunctionname]=globals_addr self.GLOBALS_MEM_CONTENT.append(Processed_functions_dict[callfunctionname][0]) ### add the offset address of the function, to the GLOBAL memory globals_addr=globals_addr+1 programm_dict[basefuncname][1][index]=occuring_globals_dict[callfunctionname] #currentprogramm_arg[index]=occuring_globals_dict[func_name] #### stitch programms of the induvidual functions together self.COMPLETE_PROGRAMM_OPCODES=[] self.COMPLETE_PROGRAMM_ARGS=[] for FuncName in function_names_inorder: self.COMPLETE_PROGRAMM_OPCODES.extend(programm_dict[FuncName][0]) self.COMPLETE_PROGRAMM_ARGS.extend(programm_dict[FuncName][1]) self.GLOBAL_STACK_SIZE=0 for offset,func_object in Processed_functions_dict.itervalues(): self.GLOBAL_STACK_SIZE=max(func_object.func_code.co_stacksize,self.GLOBAL_STACK_SIZE) ## myhdl only works with tuples self.GLOBAL_STACK_SIZE=self.GLOBAL_STACK_SIZE if len(self.GLOBALS_MEM_CONTENT)==0: self.GLOBALS_MEM_CONTENT=(0,) #needs to be a tuple of integers else: self.GLOBALS_MEM_CONTENT=tuple(self.GLOBALS_MEM_CONTENT) self.CONSTANTS_MEM_CONTENT=tuple(self.CONSTANTS_MEM_CONTENT) self.COMPLETE_PROGRAMM_OPCODES=tuple(self.COMPLETE_PROGRAMM_OPCODES) self.COMPLETE_PROGRAMM_ARGS=tuple(self.COMPLETE_PROGRAMM_ARGS) self.GLOBAL_OPCODE_ARG_MAX_VALUE=max(self.COMPLETE_PROGRAMM_ARGS) #####end class MakeProzesserByteCode ##################### |