'Modified for X2 by Mawrob, 2010 based on feedback from hippy
'
'I don't think the code will run on the 20X2 as there is a difference
'in mapping of SFR (RAM) on the 18X and 20X2; SFR locations 50 to 59 ( $32 to $3B )
'are storage locations for variables 'b0' to 'b9' on an 18X but not on the 20X2.
'Anything using those locations and expecting variable values there will find they are not.
'The tricks used to make this code work won't work on the X1 or X2 PICAXE's without being changed.
'
'Changed code to map peek and poke pointers 50->59 to 0->9
'
'Not fully tested.
'
'Original parameters left as comments
'
'**********************************************
'* 32-Bit (unsigned) maths on a PICAXE *
'* J.Leach 2006 *
'**********************************************
'****************************
'**** PROCEDURE POINTERS ****
'****************************
Symbol Procedure0StartAddress = 0
'********************************
'**** VIRTUAL PROGRAM MEMORY ****
'********************************
Eeprom 0,("+B-C*D/E=A")
'**************************
'**** PICAXE VARIABLES ****
'**************************
'Word 0 (b0 and b1)
Symbol OperandLSW = w0
Symbol OperandLSWLSB = b0
Symbol OperandLSWMSB = b1
'Word 1 (b2 and b3)
Symbol T = w1
Symbol Temp2Word = w1
Symbol InstructionOperand = b2
'Word 2 (b4 and b5)
Symbol AccumulatorLSW = w2
Symbol AccumulatorLSWLSB = b4
Symbol AccumulatorLSWMSB = b5
'Word 3 (b6 and b7)
Symbol AccumulatorMSW = w3
'Word 4 (b8 and b9)
Symbol S = w4
Symbol Temp1Word = w4
'Word 5 (b10 and b11)
Symbol OperandMSW = w5
Symbol Address = b10
Symbol Address1 = b10
Symbol Address2 = b11
'Word 6 (b12 and b13)
Symbol InstructionCode = b12
Symbol Temp1Byte = b12
Symbol ProgramCounter = b13
Symbol Temp2Byte = b13
Symbol ErrorFlag = b13
Symbol Index = b13
'*******************
'**** CONSTANTS ****
'*******************
Symbol LCDOutPin = 6 'LCD used for alerting, but other methods can be used.
'Addresses
Symbol RTStartAddress = 80
Symbol RTEndAddress = 83
Symbol DenominatorLSBAddress = 84
Symbol DenominatorMSBAddress = 85
Symbol ErrorFlagAddress = 86
Symbol GPRStartAddress = 87
Symbol ProgramCounterAddress = 97
'Error constants
Symbol ERROR_Overflow = 0
Symbol ERROR_NegativeResult = 1
Symbol ERROR_DivideByZero = 2
'Other
Symbol RTStartLessb4Address = 76'26 '(80 - 54)
Symbol GPRStartAddressLessb0Address = 87'37 '(87 - 50)
'**************
'**** MAIN ****
'**************
Main:
'Serout LCDOutPin,N2400,(254,1) 'Clear LCD. NOT really part of this module.
Pause 10000
'Example calculation: (64321 - 1052 * 761 / 4523 )
w1 = 64321
w2 = 1052
w3 = 761
w4 = 4523
ProgramCounter = Procedure0StartAddress
Gosub ExecuteProcedure
sertxd (#w5,":",#w0,CR,LF)
End
'*************************************************
'**** VIRTUAL ARITHMETIC AND LOGIC UNIT (ALU) ****
'*************************************************
Add:
'Performs : Accumulator = Accumulator + Operand
'Jumps to error routine on overflow
'Uses both words of Operand (because used by Multiply and Divide routines)
'ON EXIT: Operand is same as on entry
poke ErrorFlagAddress,ERROR_Overflow
'Add LSW
AccumulatorLSW = AccumulatorLSW + OperandLSW
If AccumulatorLSW >= OperandLSW Then Add_1
'Add Carry to MSW and jump to error routine if overflow
AccumulatorMSW = AccumulatorMSW + 1
If AccumulatorMSW = 0 Then CPU_Error
'Add MSW
Add_1:
AccumulatorMSW = AccumulatorMSW + OperandMSW
'Jump to error routine if overflow
If AccumulatorMSW < OperandMSW Then CPU_Error
Return
Subtract:
'Performs : Accumulator = Accumulator + OperandLSW
'Jumps to error routine if the result is less than zero
'Uses only the LSW of Operand
'ON EXIT: Operand is same as on entry
poke ErrorFlagAddress,ERROR_NegativeResult
'Subtract LSW
Temp1Word = AccumulatorLSW
AccumulatorLSW = AccumulatorLSW - OperandLSW
If Temp1Word >= AccumulatorLSW Then Subtract_1
'Borrow from MSW and jump to error routine if this will make the overall result
'negative.
If AccumulatorMSW = 0 Then CPU_Error
AccumulatorMSW = AccumulatorMSW - 1
'Note: No need to Subtract MSW as only OperandLSW is being used
Subtract_1:
Goto Fetch
Multiply:
'Performs : Accumulator = Accumulator * OperandLSW
'Jumps to error routine on overflow
'Uses only the LSW of Operand
'ON EXIT: Operand is corrupted
poke ErrorFlagAddress,ERROR_Overflow
'Calculate the higher multiple and keep in Accumulator
Temp1Word = AccumulatorLSW
Temp2Word = AccumulatorMSW
AccumulatorLSW = 0
AccumulatorMSW = OperandLSW * Temp2Word
Temp2Word = OperandLSW ** Temp2Word
'Check for overflow
If Temp2Word > 0 Then CPU_Error
'Calculate the lower multiple and poke in Operand
OperandMSW = Temp1Word ** OperandLSW
OperandLSW = Temp1Word * OperandLSW
'Add the multiples to peek the final result
Gosub Add
Goto Fetch
Divide:
'Performs : Accumulator = Accumulator / OperandLSW
'Jumps to error routine if divide by zero
'Uses only the LSW of Operand
'ON EXIT: Operand is corrupted
poke ErrorFlagAddress,ERROR_DivideByZero
'Check for error
If OperandLSW = 0 Then CPU_Error
'Zero the Running Total
For Address = RTStartAddress To RTEndAddress
poke Address,0
Next
'Calculate the quotient and remainder for 65535/OperandLSW
S = 65535 / OperandLSW
T = 65535 // OperandLSW
'Store the denominator
poke DenominatorLSBAddress,OperandLSWLSB
poke DenominatorMSBAddress,OperandLSWMSB
Divide_1:
'Calculate S * AccumulatorMSW in the Operand, and add to Running Total.
'Note: uses variables very carefully !
OperandLSW = AccumulatorMSW
Gosub SwapAccumulatorWithRT
OperandMSW = S ** OperandLSW
OperandLSW = S * OperandLSW
Gosub Add
'Update the running total
Gosub SwapAccumulatorWithRT
'Calculate the new Numerator
OperandMSW = 0
OperandLSW = AccumulatorLSW + AccumulatorMSW
If OperandLSW > AccumulatorMSW Then Divide_2
OperandMSW = 1
Divide_2:
AccumulatorLSW = AccumulatorMSW * T
AccumulatorMSW = AccumulatorMSW ** T
Gosub Add
'Check to see if the new numerator is a single word. Loop back if it isn't
If AccumulatorMSW > 0 Then Divide_1
Temp1Word = AccumulatorLSW
'Retrieve the running total
Gosub SwapAccumulatorWithRT
'Retrieve the denominator
peek DenominatorLSBAddress,OperandLSWLSB
peek DenominatorMSBAddress,OperandLSWMSB
'Calculate AccumulatorLSW/Demominator and store in Operand
OperandLSW = Temp1Word / OperandLSW
OperandMSW = 0
'and add to the Running total to give the final result
Gosub Add
Goto Fetch
SwapAccumulatorWithRT:
'Swaps the Accumulator value with the Running Total value
For Address1 = RTStartAddress To RTEndAddress
Address2 = Address1 - RTStartLessb4Address
peek Address1,Temp1Byte
peek Address2,Temp2Byte
poke Address1,Temp2Byte
poke Address2,Temp1Byte
Next
Return
StoreAccumulatorLSW:
'ON EXIT : The specified w0-w4 variable is loaded with the LSW of the Accumulator.
'The 'Return' statement will end the use of the Virtual CPU
'and return to 'normal' PICAXE code.
Address = InstructionOperand - "A" * 2 '+ 50
poke Address,AccumulatorLSWLSB
Address = Address + 1
poke Address,AccumulatorLSWMSB
Return
'*******************************
'**** VIRTUAL CPU ROUTINES *****
'*******************************
CPU_Error:
peek ErrorFlagAddress,ErrorFlag
Sertxd("ERROR: ",#ErrorFlag," ",CR,LF)
End
ExecuteProcedure:
'ON ENTRY: ProgramCounter has been set to the start of the Procedure
'Save the Program Counter
poke ProgramCounterAddress,ProgramCounter 'Save the ProgramCounter
'Load General Purpose registers with corresponding w0 to w4 values
For Address1 = 0 to 9'50 To 59
Address2 = Address1 + GPRStartAddressLessb0Address
peek Address1,Temp1Byte
poke Address2,Temp1Byte
Next
'Set the Accumulator to 0
AccumulatorMSW = 0
AccumulatorLSW = 0
'*************************
'**** VIRTUAL DECODER ****
'*************************
Fetch:
'Fetch an Instruction code and operand from Program Memory
peek ProgramCounterAddress,ProgramCounter 'Retrieve the ProgramCounter
Read ProgramCounter,InstructionCode
ProgramCounter = ProgramCounter + 1
Read ProgramCounter,InstructionOperand
ProgramCounter = ProgramCounter + 1
poke ProgramCounterAddress,ProgramCounter 'Save the ProgramCounter
'Load the contents of the specified Register into OperandLSW
Address = InstructionOperand - "A" * 2 + GPRStartAddress
peek Address,OperandLSWLSB
Address = Address + 1
peek Address,OperandLSWMSB
OperandMSW = 0
Execute:
'Execute the loaded Instruction
Lookdown InstructionCode,("+","-","*","/","="),Index
Branch Index,(Instruction_Add,Subtract,Multiply,Divide,StoreAccumulatorLSW)
Instruction_Add:
Gosub Add
Goto Fetch