[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) |