972 lines
31 KiB
ReStructuredText
972 lines
31 KiB
ReStructuredText
|
|
|
|
Mark II
|
|
=========================
|
|
|
|
|
|
|
|
This (and the previous incarnation) is really more of a "macro assembler"
|
|
than a compiler, and nothing like what I want it to be. It should be
|
|
tracking the "types" of registers in some enviroment that gets carried
|
|
along and picking primitives and making optimizations based on that
|
|
information.
|
|
|
|
|
|
TO replace the crude first draft I want to expand the representation of
|
|
data types.
|
|
|
|
At first I thought I might use the COLA object model but when I reviewed
|
|
it I realized that it was way too flexible for what I needed, so I"m
|
|
going to use a simple tagged record kind of a thing. There are three
|
|
"types": symbols, lists (cons lists, pairs), and integers. In order to
|
|
deal with large numbers and do double duty as strings, I'm going to let
|
|
them be made up of more than one word of memory.
|
|
|
|
Preliminary design: A record is one or more 32-bit words, the two most
|
|
signifigant bits are a type tag:
|
|
|
|
00 - Pair of pointers to other records, 30 bits left so 15 each?
|
|
10 - Symbol, the remaining 30 bits are the address of the func.
|
|
01 - Integer, the next, hmm, 6? bits are the length in words.
|
|
11 - escape hatch to COLA maybe?
|
|
|
|
Deets: For pairs, the empty list is still 0 and by leaving 0 in RAM[0]
|
|
it's "safe" to deref it. Each half of the rest of the word (15 bits) is
|
|
an offset (not a direct pointer) from the pair to the member record.
|
|
|
|
For symbols, the rest of the word is the direct pointer to the machine
|
|
code of the function denoted by the symbol. I might add some additional
|
|
data to the head of the record because the CPU doesn't have 30 address
|
|
lines. I'm assuming that the (as yet unwritten) parser will take care of
|
|
looking up the symbols at parse time, but it would also be possible to
|
|
point to a integer that represents the string name of the function and do
|
|
lookup during evaluation, or during some intermediate stage.
|
|
|
|
For ints, I'm putting a little length field in the record, 0 length means
|
|
the integer's bits all fit in the rest of the record word. If the length
|
|
is 1 the integer is in the following word (but what if the rest of the
|
|
record word was a pointer to the data word? Could save space for popular
|
|
integers, eh?) If the length is greater than 1 the rest of the bytes in
|
|
the record word are included in the intger(?)
|
|
|
|
01000000|byte|byte|byte <- three bytes of integer.
|
|
|
|
01000001|0000|0000|0000 <- (Pointer to data maybe?)
|
|
byte|byte|byte|byte <- four bytes of integer.
|
|
|
|
Or how about...
|
|
|
|
010nnnnn|byte|byte|byte <- 29 bits of immediate integer
|
|
011nnnnn|byte|byte|byte <- length and offset packed in 29 bits?
|
|
pointing to a stretch of words in RAM
|
|
|
|
If the offset is limited to 16 bits that leaves 13 bits for the length.
|
|
8K 32-bit words is 262144 bits, and 2^262144 is a pretty big number.
|
|
|
|
It doesn't matter yet because I'm not about to implement math yet.
|
|
|
|
So let's see how bad it is to rewrite the compiler to make it implement
|
|
this new stuff.
|
|
|
|
main loop
|
|
-------------------------------------
|
|
|
|
|
|
if_zero(EXPR, HALT)
|
|
|
|
No change to the iplementation is needed.
|
|
|
|
deref(EXPR) loads the record at the address in expr register into that
|
|
register, but now we are going to need to remember that address to add
|
|
it to the offset in the record to find the records of the head and tail
|
|
records.
|
|
|
|
Change it to deref(EXPR, TEMP0) and keep the address around in TEMP0.
|
|
|
|
split_word(TERM, EXPR) puts the record pointed to by head of the expr
|
|
record into term register and leave the address of the tail record in
|
|
expr. THe address of the tail record is just the last 15 bits plus the
|
|
address in TEMP0.
|
|
|
|
The address of the head record is bits [30:15] of the record plus the
|
|
address in TEMP0.
|
|
|
|
SO, load the head record address bits into ToAddr and then add FromAddr
|
|
|
|
ior_imm(ToAddr, From, -15), % roll right 15 bits
|
|
% No need to mask off high bits as the type tag for pairs is 00
|
|
add(ToAddr, ToAddr, FromAddr),
|
|
|
|
load_word(To, ToAddr, 0), % Bring the record in from RAM.
|
|
|
|
and_imm(From, From, 0x7fff), % Mask off lower 15 bits.
|
|
add(From, From, FromAddr), % Add the address to the offset.
|
|
|
|
|
|
If a record can only be created after its parts and the parts are being
|
|
allocated in strictly ascending (or descending) order of addresses then
|
|
the offsets will always be negative (or positive). SInce it's easier to
|
|
deal with positive offsets and it's just as easy to allocate up as down,
|
|
I'm going to do that.
|
|
|
|
|
|
Next, we must check if the term is a literal (not a symbol)
|
|
|
|
That involves rolling the value to get the top two bits and then checking
|
|
whether they are 10 or not.
|
|
|
|
lookup(DICT_PTR, DICT_TOP, TERM, HALT)
|
|
|
|
It turns out that you don;t need anything but the record since it's
|
|
already been looked up. The symbol contains the jump address.
|
|
|
|
|
|
|
|
Next, push
|
|
|
|
push(TOS, TERM, SP)
|
|
|
|
There's a note saying
|
|
|
|
set(sp, 2), % Reg 2 points to just under top of stack.
|
|
|
|
But I've forgotten if that's exactly true. I want to just point to TOS
|
|
pair record in SP. If that's the case, then the PUSH operation is:
|
|
|
|
Since the record we are constructing is going to have the rest of the
|
|
stack as its tail and it's going to be written to the next word in RAM
|
|
after (before) the SP (the address of the stack/tail) the offset is +4.
|
|
|
|
The address of the term is in a register, the address of the pair record
|
|
that we are contrsucting will be SP - 4, to get the offset we have to
|
|
subtract that from the term's address. Since we need it anyway, and
|
|
we're going to do it sooner or later, let's subtract 4 from the SP right
|
|
off:
|
|
|
|
sp = sp - 4
|
|
|
|
Then we can use it to calculate the offset and put it in tos:
|
|
|
|
tos = &temp - sp
|
|
tos = tos << 15
|
|
|
|
If I was as slick as I like to pretend I would insert a check here that
|
|
the two high bits are indeed 00. ...
|
|
|
|
With the offset of the term in the tos register already we just have to
|
|
OR 4:
|
|
|
|
tos = tos | 4
|
|
|
|
And write it to the (already decremented) sp.
|
|
|
|
ram[sp] = tos
|
|
|
|
|
|
cons
|
|
------------------------------
|
|
|
|
[グ,ケ,ゲ,ド,ゴ,サ],ヮ(cons),
|
|
|
|
グ pop(TEMP0, TOS) split_word(TEMP0, TOS), high_half_to(To, From), swap_halves(To, From), ror_imm(To, From, 16)
|
|
low_half(To) and_imm(Reg, Reg, 0xffff)
|
|
low_half(From) and_imm(Reg, Reg, 0xffff)
|
|
|
|
Puts the term on tos (the list to cons onto) into temp0 and points tos
|
|
deref(TOS) to the value under tos (the item to cons onto the list.)
|
|
|
|
ケ high_half(TEMP1, TOS) mov_imm_with_shift(0, 0xffff), Mask off the high half of (new) tos to isolate value.
|
|
and(TEMP1, TOS, 0)
|
|
ゲ or_inplace(TEMP0, TEMP1) ior(TEMP0, TEMP0, TEMP1) Combines value with the list in a new pair record.
|
|
ド write_cell(TEMP0, SP) add_imm(SP, SP, 4), Writes the new pair cell word to ++sp.
|
|
store_word(TEMP0, SP, 0)
|
|
ゴ low_half(TOS) and_imm(TOS, TOS, 0xffff) Delete the reference to second item down.
|
|
サ merge(SP, TOS) lsl_imm(0, SP, 16), Make a new pair record from the SP which points to the new cons'd list
|
|
ior(TOS, TOS, 0), and TOS which points to the rest of the stack. This record is then the
|
|
add_imm(SP, SP, 4) new TOS pair cell word, and we let the mainloop write it to RAM for us.
|
|
|
|
So now that i've recreated it, what is it doing?
|
|
|
|
⦾(グ, pop(TEMP0, TOS))
|
|
⦾(ケ, high_half(TEMP1, TOS))
|
|
⦾(ゲ, or_inplace(TEMP0, TEMP1))
|
|
⦾(ド, write_cell(TEMP0, SP))
|
|
⦾(ゴ, low_half(TOS))
|
|
⦾(サ, merge(SP, TOS))
|
|
|
|
⟐(pop(Reg, TOS)) --> ⟐([split_word(Reg, TOS), deref(TOS)]).
|
|
⟐(high_half(To, From)) --> [mov_imm_with_shift(0, 0xffff), and(To, From, 0)].
|
|
⟐(or_inplace(To, From)) --> [ior(To, To, From)].
|
|
⟐(write_cell(From, SP)) --> [add_imm(SP, SP, 4), store_word(From, SP, 0)].
|
|
⟐( low_half(Reg)) --> [and_imm(Reg, Reg, 0xffff)].
|
|
⟐(merge(SP, TOS)) -->
|
|
[lsl_imm(0, SP, 16),
|
|
ior(TOS, TOS, 0),
|
|
add_imm(SP, SP, 4)].
|
|
|
|
|
|
This blows, just write it in assembly already.
|
|
|
|
|
|
-------------------------------
|
|
|
|
TO review, at this point, when we jump to the machine code of a
|
|
definition, the following registers hold:
|
|
|
|
EXPR - the record word of the expression.
|
|
EXPR_addr - the address of the next cell of the expression list.
|
|
TERM - the term's record word.
|
|
TermAddr - the address of the term.
|
|
SP - points to TOS record in RAM
|
|
TOS - the record word of TOS
|
|
|
|
address of the list to append to is SP + TOS[30:15]
|
|
the address of the second stack cell is SP + TOS[15:0]
|
|
the address of the second item on the stack is (SP + TOS[15:0]) + ram[SP + TOS[15:0]][30:15]
|
|
the address of the third stack cell is (SP + TOS[15:0]) + ram[SP + TOS[15:0]][15: 0]
|
|
|
|
we need to create
|
|
|
|
[SP - 4] -> 00:(address of the second item on the stack):(address of the list to append to)
|
|
[SP - 8] -> 00:(address of the record above) :(address of the third stack cell)
|
|
|
|
Each of the addresses above must be converted to offsets from their
|
|
respective records.
|
|
|
|
ror_imm(TEMP0, TOS, 15), % TEMP0 := TOS >> 15
|
|
add(TEMP0, TEMP0, SP)
|
|
% TEMP0 = SP + TOS[30:15] Address of the list to which to append.
|
|
|
|
and_imm(TOS, TOS, 0x7fff), % get the offset of the tail of the stack
|
|
add(TOS, TOS, SP)
|
|
% TOS = SP + TOS[15:0] Address of the second stack cell.
|
|
|
|
% the address of the second item on the stack is (TOS) + ram[TOS][30:15]
|
|
% the address of the third stack cell is (TOS) + ram[TOS][15: 0]
|
|
|
|
load_word(TEMP1, TOS, 0), % TOS := TOS << 15
|
|
% TEMP1 contains the record of the second stack cell.
|
|
|
|
% the address of the second item on the stack is (TOS) + TEMP1[30:15]
|
|
% the address of the third stack cell is (TOS) + TEMP1[15: 0]
|
|
|
|
ror_imm(TEMP2, TEMP1, 15), % TEMP2 := TEMP1 >> 15
|
|
add(TEMP2, TEMP2, TOS)
|
|
% TEMP2 contains the address of the second item on the stack
|
|
|
|
and_imm(TEMP3, TEMP1, 0x7fff), % get the offset of the third stack cell
|
|
add(TEMP3, TEMP1, TOS)
|
|
% TEMP3 = TOS + TEMP1[15:0] the address of the third stack cell
|
|
|
|
|
|
we need to create
|
|
|
|
[SP - 4] -> 00:(address of the second item on the stack):(address of the list to append to)
|
|
[SP - 8] -> 00:(address of the record above) :(address of the third stack cell)
|
|
4 << 15
|
|
Each of the addresses above must be converted to offsets from their
|
|
respective records.
|
|
|
|
sub_imm(SP, SP, 4),
|
|
sub(TEMP2, TEMP2, SP),
|
|
sub(TEMP0, TEMP0, SP),
|
|
lsl_imm(TEMP2, TEMP2, 15), % TEMP2 := TEMP2 << 15
|
|
ior(TEMP2, TEMP2, TEMP0),
|
|
store_word(TEMP2, SP, 0),
|
|
|
|
|
|
sub_imm(SP, SP, 4),
|
|
sub(TEMP3, TEMP3, SP),
|
|
mov_imm(TEMP2, 4),
|
|
lsl_imm(TEMP2, TEMP2, 15), % TEMP2 := 4 << 15
|
|
ior(TEMP2, TEMP2, TEMP3),
|
|
store_word(TEMP2, SP, 0),
|
|
|
|
I had some bugs because I forgot that when the offset is zero the base
|
|
should not be added/subtracted: zero offset means the value is the empty
|
|
list.
|
|
|
|
If offsets can only be positive (as I have it now) then record pairs on
|
|
the stack can only point to cells above them. That implies that symbols
|
|
must be allocated above the stack in RAM. However, I am constructing the
|
|
code library from low mem upwards, and if I include the symbol cells in
|
|
the function machine code as a kind of header (as I intend to) they'll be
|
|
below the stack. I could put the symbol cells together in a clump just
|
|
above the stack but then I would need to implement org() and modify the
|
|
for_serial/2 relation to emit more than one "patch" for the bootloader.
|
|
|
|
I could modify the implementation to allow for negative offsets. That
|
|
would be a little tricky but probably easier at the moment than adding
|
|
org() and changing for_serial/2. It would also facilitate writing lists
|
|
in "reverse" order (the head cell is above the tail in RAM) which is
|
|
useful for appending lists to other lists.
|
|
|
|
Yeah, I think that's the way to go...
|
|
|
|
---------------------------------------------
|
|
|
|
There's soething fishey with the symbols now that they are in the header
|
|
of the machine code. Each symbol's pointer field points to the next cell,
|
|
which seems really redundant. We need some symbol record to
|
|
differentiate from lists and ints. Maybe if more information was in the
|
|
header? Like the name of the function? It would make more sense?
|
|
|
|
Right now I'm assuming that the eventual parser would be looking up
|
|
symbols at parse-time and reusing the header symbols rather than
|
|
allocating cells for new ones. If the symbols were kept apart from the
|
|
machine code then it makes sense for them to have pointers?
|
|
|
|
Maybe I can dispense with symbol records by modifying the
|
|
is-this-a-symbol code to just check if the address is below the end of
|
|
the library code.
|
|
|
|
------------------------------------
|
|
|
|
|
|
[ザ,シ],ヮ(dup),
|
|
|
|
ザ swap_halves(TOS)
|
|
シ push(TOS, TOS, SP)
|
|
|
|
|
|
------------------------------------
|
|
|
|
|
|
[グ,ス,[],[ジ,ス,[ズ,セ,ス,[ゼ,ソ],[タ,ゾ],ヰ,ヂ],ヱ],ヰ,チ],ヮ(i),
|
|
|
|
グ, pop(TEMP0, TOS)
|
|
ス, if_zero(TEMP0)
|
|
ジ, add_const(TEMP3, SP, 4)
|
|
ズ, deref(TEMP0)
|
|
セ, chop_word(TEMP1, TEMP0)
|
|
ゼ, or_inplace(TEMP1, EXPR)
|
|
ソ, asm(mov(EXPR, TEMP3))
|
|
タ, add_const(TEMP2, SP, 8)
|
|
ゾ, or_inplace(TEMP1, TEMP2)
|
|
ヂ, write_cell(TEMP1, SP)
|
|
チ, add_const(SP, SP, 4)
|
|
|
|
|
|
|
|
⦾([P, T, E, ヰ|Terms], [br(Predicate, Then, Else)|Ts]) -->
|
|
⦾([P, T, E, Terms], [Predicate, Then, Else, Ts]).
|
|
|
|
⦾([P, B, ヱ|Terms], [repeat_until(Predicate, Body)|Ts]) -->
|
|
⦾([P, B, Terms], [Predicate, Body, Ts]).
|
|
|
|
|
|
|
|
[
|
|
グ, pop(TEMP0, TOS)
|
|
ス, if_zero(TEMP0)
|
|
[], Then
|
|
[ Else
|
|
ジ, add_const(TEMP3, SP, 4)
|
|
ス, if_zero(TEMP0)
|
|
[ Body
|
|
ズ, deref(TEMP0)
|
|
セ, chop_word(TEMP1, TEMP0)
|
|
ス, if_zero(TEMP0)
|
|
[ Then
|
|
ゼ, or_inplace(TEMP1, EXPR)
|
|
ソ asm(mov(EXPR, TEMP3))
|
|
],
|
|
[ Else
|
|
タ, add_const(TEMP2, SP, 8)
|
|
ゾ or_inplace(TEMP1, TEMP2)
|
|
],
|
|
ヰ, br(Predicate, Then, Else)
|
|
ヂ write_cell(TEMP1, SP)
|
|
],
|
|
ヱ repeat_until(Predicate, Body)
|
|
],
|
|
ヰ, br(Predicate, Then, Else)
|
|
チ add_const(SP, SP, 4)
|
|
],
|
|
ヮ(i),
|
|
|
|
|
|
------------------------------------------
|
|
|
|
[ヶ,ペ],ワ(new),
|
|
|
|
ヶ, low_half(TOS, SP)
|
|
ペ, write_cell(TOS, SP)
|
|
|
|
|
|
------------------------------------------
|
|
|
|
|
|
[ナ,ズ,セ,ネ,ヒ,ド,ャ,ペ],ワ(swap),
|
|
|
|
ナ, low_half(TEMP0, TOS)
|
|
ズ, deref(TEMP0)
|
|
セ, chop_word(TEMP1, TEMP0)
|
|
ネ, chop_word(TEMP2, TOS)
|
|
ヒ, or_inplace(TEMP0, TEMP2)
|
|
ド, write_cell(TEMP0, SP)
|
|
ャ, asm(ior(TOS, TEMP1, SP))
|
|
ペ, write_cell(TOS, SP)
|
|
|
|
|
|
--------------------------------------
|
|
|
|
Debugging definitions
|
|
|
|
swons 0xd2 load R[0] <- ram[R[0] + 0x34c]
|
|
> 0xd3 mov R[2] <- 0x354
|
|
0xd4 BR T 0x2 immediate
|
|
0xd5 BR F -0x69fffc immediate and R[15] <- PC + 1
|
|
0xd6 BR GT -0x4c0000 immediate and R[15] <- PC + 1
|
|
dodef 0xd7 mov R[7] <- 0x4
|
|
0xd8 sub R[0] <- R[0] 0x4 immediate
|
|
|
|
Q: Is 0x354 >> 2 == 0xd5 ?
|
|
|
|
In [1]: 0x354 >> 2 == 0xd5
|
|
Out[1]: True
|
|
|
|
Okay then.
|
|
|
|
|
|
> dodef 0xd7 mov R[7] <- 0x4
|
|
0xd8 sub R[0] <- R[0] 0x4 immediate
|
|
0xd9 sub R[2] <- R[2] 0x0 immediate
|
|
0xda BR EQ 0x2 immediate
|
|
0xdb sub R[2] <- R[2] R[0]
|
|
0xdc and R[2] <- R[2] 0x7fff immediate
|
|
|
|
|
|
0xff4 r0
|
|
0x354 r2
|
|
|
|
|
|
> 0xde ior R[2] <- R[2] R[7]
|
|
0xdf store R[2] -> ram[R[0]]
|
|
0xe0 mov R[7] <- 0x168
|
|
0xe1 add R[7] <- R[7] 0x4 immediate
|
|
0xe2 BR T R[7]
|
|
expressi 0xe3 BR F 0x740004 immediate and R[15] <- PC + 1
|
|
|
|
0x39b00004 r2
|
|
|
|
0xe0 mov R[7] <- 0x168
|
|
> 0xe1 add R[7] <- R[7] 0x4 immediate
|
|
0xe2 BR T R[7]
|
|
expressi 0xe3 BR F 0x740004 immediate and R[15] <- PC + 1
|
|
|
|
|
|
0x16c r7 = 364 decimal
|
|
|
|
0x5b I machine code in words
|
|
|
|
In [8]: 0x16c >> 2 == 0x5b
|
|
Out[8]: True
|
|
|
|
i 0x5a load R[0] <- ram[R[0] + 0x16c]
|
|
> 0x5b lsl R[6] <- R[2] 0x2 immediate
|
|
0x5c asr R[6] <- R[6] 0x11 immediate
|
|
0x5d BR EQ 0x1 immediate
|
|
0x5e add R[6] <- R[6] R[0]
|
|
0x5f lsl R[2] <- R[2] 0x11 immediate
|
|
0x60 asr R[2] <- R[2] 0x11 immediate
|
|
|
|
and then...
|
|
|
|
i 0x5a load R[0] <- ram[R[0] + 0x16c]
|
|
0x5b lsl R[6] <- R[2] 0x2 immediate
|
|
0x5c asr R[6] <- R[6] 0x11 immediate
|
|
0x5d BR EQ 0x1 immediate
|
|
> 0x5e add R[6] <- R[6] R[0]
|
|
0x5f lsl R[2] <- R[2] 0x11 immediate
|
|
0x60 asr R[2] <- R[2] 0x11 immediate
|
|
0x61 BR EQ 0x1 immediate
|
|
0x62 add R[2] <- R[2] R[0]
|
|
0x63 sub R[6] <- R[6] 0x0 immediate
|
|
|
|
0x354 r6 check
|
|
|
|
0x5e add R[6] <- R[6] R[0]
|
|
0x5f lsl R[2] <- R[2] 0x11 immediate
|
|
0x60 asr R[2] <- R[2] 0x11 immediate
|
|
0x61 BR EQ 0x1 immediate
|
|
> 0x62 add R[2] <- R[2] R[0]
|
|
0x63 sub R[6] <- R[6] 0x0 immediate
|
|
0x64 BR EQ 0x22 immediate
|
|
0x65 sub R[10] <- R[0] 0x4 immediate
|
|
|
|
0xff8 r2
|
|
|
|
0x61 BR EQ 0x1 immediate
|
|
0x62 add R[2] <- R[2] R[0]
|
|
0x63 sub R[6] <- R[6] 0x0 immediate
|
|
#117 0x64 BR EQ 0x22 immediate
|
|
> 0x65 sub R[10] <- R[0] 0x4 immediate
|
|
0x66 mov R[9] <- 0x4
|
|
0x67 load R[3] <- ram[R[6]]
|
|
iball 0x68 lsl R[7] <- R[3] 0x2 immediate
|
|
0x69 asr R[7] <- R[7] 0x11 immediate
|
|
0x6a BR EQ 0x1 immediate
|
|
|
|
line 120
|
|
|
|
#120 0x65 sub R[10] <- R[0] 0x4 immediate
|
|
0x66 mov R[9] <- 0x4
|
|
> 0x67 load R[3] <- ram[R[6]]
|
|
iball 0x68 lsl R[7] <- R[3] 0x2 immediate
|
|
0x69 asr R[7] <- R[7] 0x11 immediate
|
|
0x6a BR EQ 0x1 immediate
|
|
0x6b add R[7] <- R[7] R[6]
|
|
0x6c lsl R[8] <- R[3] 0x11 immediate
|
|
|
|
line 123
|
|
|
|
0xff960004 r3
|
|
|
|
iball 0x68 lsl R[7] <- R[3] 0x2 immediate
|
|
0x69 asr R[7] <- R[7] 0x11 immediate
|
|
0x6a BR EQ 0x1 immediate
|
|
> 0x6b add R[7] <- R[7] R[6]
|
|
0x6c lsl R[8] <- R[3] 0x11 immediate
|
|
0x6d asr R[8] <- R[8] 0x11 immediate
|
|
0x6e BR EQ 0x1 immediate
|
|
0x6f add R[8] <- R[8] R[6]
|
|
0x70 mov R[6] <- R[8]
|
|
|
|
0x280 r7 Address of swons def list? of swap symbol?
|
|
|
|
In [4]: w.cpu.R[7]
|
|
Out[4]: 640L
|
|
|
|
In [5]: hex(_)
|
|
Out[5]: '0x280L'
|
|
|
|
In [6]: w.cpu.ram[w.cpu.R[7]]
|
|
Out[6]: 2147484292L
|
|
|
|
In [7]: bin(_)
|
|
Out[7]: '0b10000000000000000000001010000100'
|
|
|
|
In [8]: w.syms.keys()
|
|
Out[8]: [160, 35, 7, 104, 44, 45, 14, 205, 48, 200, 210, 227, 86, 215, 90, 157]
|
|
|
|
In [9]: 640 >> 2
|
|
Out[9]: 160
|
|
|
|
In [10]: w.syms[160]
|
|
Out[10]: 'swap'
|
|
|
|
0x280 r7 points to swap symbol record.
|
|
===================================================
|
|
|
|
0x6b add R[7] <- R[7] R[6]
|
|
0x6c lsl R[8] <- R[3] 0x11 immediate
|
|
0x6d asr R[8] <- R[8] 0x11 immediate
|
|
0x6e BR EQ 0x1 immediate
|
|
> 0x6f add R[8] <- R[8] R[6]
|
|
#127 0x70 mov R[6] <- R[8]
|
|
0x71 sub R[0] <- R[0] 0x4 immediate
|
|
0x72 sub R[8] <- R[8] 0x0 immediate
|
|
0x73 BR EQ 0x4 immediate
|
|
|
|
0x358 r8
|
|
|
|
> 0x70 mov R[6] <- R[8]
|
|
|
|
line 127
|
|
|
|
0x70 mov R[6] <- R[8]
|
|
0x71 sub R[0] <- R[0] 0x4 immediate
|
|
0x72 sub R[8] <- R[8] 0x0 immediate
|
|
> 0x73 BR EQ 0x4 immediate
|
|
0x74 lsl R[7] <- R[7] 0xf immediate
|
|
0x75 ior R[7] <- R[7] R[9]
|
|
0x76 store R[7] -> ram[R[0]]
|
|
0x77 BR T 0xb immediate
|
|
0x78 sub R[7] <- R[7] 0x0 immediate
|
|
|
|
line 129
|
|
|
|
0x73 BR EQ 0x4 immediate
|
|
0x74 lsl R[7] <- R[7] 0xf immediate
|
|
0x75 ior R[7] <- R[7] R[9]
|
|
> 0x76 store R[7] -> ram[R[0]]
|
|
0x77 BR T 0xb immediate
|
|
|
|
0x1400004 r7 -> ram[r[0]] w/ r0 = 0xff0
|
|
|
|
saved foobar1
|
|
|
|
I think I found it. Not subtracting SP from r7 address
|
|
before merge_and_store(TEMP1, TEMP3, SP) on line #134.
|
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
jmp @ 0x77 to 0xb -> 0x83
|
|
repeat
|
|
> 0x83 sub R[6] <- R[6] 0x0 immediate
|
|
0x84 BR EQ 0x1 immediate
|
|
0x85 BR T -0x1f immediate
|
|
0x86 mov R[1] <- R[10]
|
|
0x87 load R[7] <- ram[R[2]]
|
|
0x88 lsl R[6] <- R[7] 0x2 immediate
|
|
|
|
|
|
0x85 + -0x1f
|
|
|
|
> 0x67 load R[3] <- ram[R[6]]
|
|
iball 0x68 lsl R[7] <- R[3] 0x2 immediate
|
|
0x69 asr R[7] <- R[7] 0x11 immediate
|
|
0x6a BR EQ 0x1 immediate
|
|
0x6b add R[7] <- R[7] R[6]
|
|
0x6c lsl R[8] <- R[3] 0x11 immediate
|
|
|
|
back to line 123
|
|
|
|
iball 0x68 lsl R[7] <- R[3] 0x2 immediate
|
|
0x69 asr R[7] <- R[7] 0x11 immediate
|
|
0x6a BR EQ 0x1 immediate
|
|
0x6b add R[7] <- R[7] R[6]
|
|
0x6c lsl R[8] <- R[3] 0x11 immediate
|
|
0x6d asr R[8] <- R[8] 0x11 immediate
|
|
> 0x6e BR EQ 0x1 immediate
|
|
0x6f add R[8] <- R[8] R[6]
|
|
0x70 mov R[6] <- R[8]
|
|
0x71 sub R[0] <- R[0] 0x4 immediate
|
|
0x72 sub R[8] <- R[8] 0x0 immediate
|
|
0x73 BR EQ 0x4 immediate
|
|
|
|
0xc0 r7
|
|
0x0 r8
|
|
|
|
0x6e BR EQ 0x1 immediate
|
|
0x6f add R[8] <- R[8] R[6]
|
|
0x70 mov R[6] <- R[8]
|
|
0x71 sub R[0] <- R[0] 0x4 immediate
|
|
0x72 sub R[8] <- R[8] 0x0 immediate
|
|
> 0x73 BR EQ 0x4 immediate
|
|
0x74 lsl R[7] <- R[7] 0xf immediate
|
|
0x75 ior R[7] <- R[7] R[9]
|
|
0x76 store R[7] -> ram[R[0]]
|
|
0x77 BR T 0xb immediate
|
|
0x78 sub R[7] <- R[7] 0x0 immediate
|
|
|
|
We take the high road this time
|
|
|
|
0x73 BR EQ 0x4 immediate
|
|
0x74 lsl R[7] <- R[7] 0xf immediate
|
|
0x75 ior R[7] <- R[7] R[9]
|
|
0x76 store R[7] -> ram[R[0]]
|
|
0x77 BR T 0xb immediate
|
|
> 0x78 sub R[7] <- R[7] 0x0 immediate
|
|
0x79 BR EQ 0x2 immediate
|
|
0x7a sub R[7] <- R[7] R[0]
|
|
0x7b and R[7] <- R[7] 0x7fff immediate
|
|
0x7c sub R[1] <- R[1] 0x0 immediate
|
|
0x7d BR EQ 0x2 immediate
|
|
|
|
|
|
r7 = 0xc0
|
|
r0 = 0xfec
|
|
|
|
so, @0x7a, r7 <- r7 - r0 -> -3884 or -0xf2c
|
|
Hmm...
|
|
|
|
0x78 sub R[7] <- R[7] 0x0 immediate
|
|
0x79 BR EQ 0x2 immediate
|
|
0x7a sub R[7] <- R[7] R[0]
|
|
> 0x7b and R[7] <- R[7] 0x7fff immediate
|
|
0x7c sub R[1] <- R[1] 0x0 immediate
|
|
0x7d BR EQ 0x2 immediate
|
|
0x7e sub R[1] <- R[1] R[0]
|
|
0x7f and R[1] <- R[1] 0x7fff immediate
|
|
0x80 lsl R[7] <- R[7] 0xf immediate
|
|
|
|
|
|
|
|
0x7b and R[7] <- R[7] 0x7fff immediate
|
|
0x7c sub R[1] <- R[1] 0x0 immediate
|
|
0x7d BR EQ 0x2 immediate
|
|
> 0x7e sub R[1] <- R[1] R[0]
|
|
0x7f and R[1] <- R[1] 0x7fff immediate
|
|
0x80 lsl R[7] <- R[7] 0xf immediate
|
|
0x81 ior R[7] <- R[7] R[1]
|
|
0x82 store R[7] -> ram[R[0]]
|
|
|
|
0xfffff3ac r1 ... 0x73ac
|
|
|
|
0x7e sub R[1] <- R[1] R[0]
|
|
0x7f and R[1] <- R[1] 0x7fff immediate
|
|
0x80 lsl R[7] <- R[7] 0xf immediate
|
|
0x81 ior R[7] <- R[7] R[1]
|
|
> 0x82 store R[7] -> ram[R[0]]
|
|
0x83 sub R[6] <- R[6] 0x0 immediate
|
|
0x84 BR EQ 0x1 immediate
|
|
0x85 BR T -0x1f immediate
|
|
0x86 mov R[1] <- R[10]
|
|
0x87 load R[7] <- ram[R[2]]
|
|
|
|
0x386a73ac r7 !?
|
|
|
|
0x82 store R[7] -> ram[R[0]]
|
|
0x83 sub R[6] <- R[6] 0x0 immediate
|
|
0x84 BR EQ 0x1 immediate
|
|
0x85 BR T -0x1f immediate
|
|
> 0x86 mov R[1] <- R[10]
|
|
0x87 load R[7] <- ram[R[2]]
|
|
0x88 lsl R[6] <- R[7] 0x2 immediate
|
|
0x89 asr R[6] <- R[6] 0x11 immediate
|
|
0x8a BR EQ 0x1 immediate
|
|
0x8b add R[6] <- R[6] R[2]
|
|
|
|
line 141
|
|
|
|
> 0x87 load R[7] <- ram[R[2]]
|
|
|
|
line 146
|
|
|
|
0x4 r7 "the record of the second stack cell"
|
|
empty list followed by the record one cell above
|
|
|
|
0x87 load R[7] <- ram[R[2]]
|
|
* 0x88 lsl R[6] <- R[7] 0x2 immediate
|
|
* 0x89 asr R[6] <- R[6] 0x11 immediate
|
|
* 0x8a BR EQ 0x1 immediate
|
|
* 0x8b add R[6] <- R[6] R[2]
|
|
* 0x8c lsl R[7] <- R[7] 0x11 immediate
|
|
* 0x8d asr R[7] <- R[7] 0x11 immediate
|
|
* 0x8e BR EQ 0x1 immediate
|
|
* 0x8f add R[7] <- R[7] R[2]
|
|
> 0x90 sub R[0] <- R[0] 0x4 immediate
|
|
0x91 sub R[6] <- R[6] 0x0 immediate
|
|
0x92 BR EQ 0x2 immediate
|
|
0x93 sub R[6] <- R[6] R[0]
|
|
0x94 and R[6] <- R[6] 0x7fff immediate
|
|
0x95 sub R[7] <- R[7] 0x0 immediate
|
|
|
|
at line 150
|
|
0x0 r6
|
|
0xffc r7
|
|
|
|
TEMP0 = HeadAddr, TEMP1 = TailAddr
|
|
|
|
mkII.2.2 saved here.
|
|
|
|
0x90 sub R[0] <- R[0] 0x4 immediate
|
|
0x91 sub R[6] <- R[6] 0x0 immediate
|
|
0x92 BR EQ 0x2 immediate
|
|
0x93 sub R[6] <- R[6] R[0]
|
|
0x94 and R[6] <- R[6] 0x7fff immediate
|
|
0x95 sub R[7] <- R[7] 0x0 immediate
|
|
0x96 BR EQ 0x2 immediate
|
|
0x97 sub R[7] <- R[7] R[0]
|
|
0x98 and R[7] <- R[7] 0x7fff immediate
|
|
0x99 lsl R[6] <- R[6] 0xf immediate
|
|
0x9a ior R[6] <- R[6] R[7]
|
|
> 0x9b store R[6] -> ram[R[0]]
|
|
0x9c BR T -0x8f immediate
|
|
new 0x9d load R[0] <- ram[R[0] + 0x278]
|
|
0x9e mov R[5] <- 0x0
|
|
0x9f BR T -0x7d immediate
|
|
swap 0xa0 load R[0] <- ram[R[0] + 0x284]
|
|
|
|
|
|
lie 151-152 end of I machine code
|
|
|
|
0x14 r6 20 decimal 5 words/cells above
|
|
0xfe8 r0
|
|
|
|
> main 0xe sub R[1] <- R[1] 0x0 immediate
|
|
0xf BR EQ 0x1f immediate
|
|
0x10 load R[4] <- ram[R[1]]
|
|
0x11 lsl R[5] <- R[4] 0x2 immediate
|
|
0x12 asr R[5] <- R[5] 0x11 immediate
|
|
0x13 BR EQ 0x1 immediate
|
|
|
|
0xff0 r1
|
|
|
|
|
|
|
|
saved mkII.2.3
|
|
|
|
main 0xe sub R[1] <- R[1] 0x0 immediate
|
|
0xf BR EQ 0x1f immediate
|
|
> 0x10 load R[4] <- ram[R[1]]
|
|
0x11 lsl R[5] <- R[4] 0x2 immediate
|
|
0x12 asr R[5] <- R[5] 0x11 immediate
|
|
0x13 BR EQ 0x1 immediate
|
|
0x14 add R[5] <- R[5] R[1]
|
|
0x15 lsl R[6] <- R[4] 0x11 immediate
|
|
|
|
line 50
|
|
0x1400004 r4
|
|
|
|
main 0xe sub R[1] <- R[1] 0x0 immediate
|
|
0xf BR EQ 0x1f immediate
|
|
0x10 load R[4] <- ram[R[1]]
|
|
0x11 lsl R[5] <- R[4] 0x2 immediate
|
|
0x12 asr R[5] <- R[5] 0x11 immediate
|
|
0x13 BR EQ 0x1 immediate
|
|
> 0x14 add R[5] <- R[5] R[1]
|
|
0x15 lsl R[6] <- R[4] 0x11 immediate
|
|
0x16 asr R[6] <- R[6] 0x11 immediate
|
|
0x17 BR EQ 0x1 immediate
|
|
0x18 add R[6] <- R[6] R[1]
|
|
0x19 load R[3] <- ram[R[5]]
|
|
|
|
0x1270 r5
|
|
|
|
0x14 add R[5] <- R[5] R[1]
|
|
0x15 lsl R[6] <- R[4] 0x11 immediate
|
|
0x16 asr R[6] <- R[6] 0x11 immediate
|
|
0x17 BR EQ 0x1 immediate
|
|
> 0x18 add R[6] <- R[6] R[1]
|
|
0x19 load R[3] <- ram[R[5]]
|
|
0x1a mov R[1] <- R[6]
|
|
0x1b asr R[6] <- R[3] 0x1e immediate
|
|
0x1c and R[6] <- R[6] 0x2 immediate
|
|
0x1d sub R[6] <- R[6] 0x2 immediate
|
|
|
|
0xff4 r6
|
|
|
|
> 0x19 load R[3] <- ram[R[5]]
|
|
|
|
line 53
|
|
0x0 r3 ram[0x1270]
|
|
|
|
> 0x1a mov R[1] <- R[6]
|
|
|
|
line 56
|
|
|
|
0xff4 r1
|
|
|
|
|
|
0x1d sub R[6] <- R[6] 0x2 immediate
|
|
0x1e BR NE 0x4 immediate
|
|
0x1f mov R[6] <- 0x3fff0000
|
|
0x20 ior R[6] <- R[6] 0xffff immediate
|
|
0x21 and R[6] <- R[6] R[3]
|
|
0x22 BR T R[6]
|
|
> push 0x23 sub R[0] <- R[0] 0x4 immediate
|
|
0x24 sub R[5] <- R[5] 0x0 immediate
|
|
0x25 BR EQ 0x6 immediate
|
|
0x26 sub R[2] <- R[5] R[0]
|
|
0x27 BR HI 0x1 immediate
|
|
0x28 and R[2] <- R[2] 0x7fff immediate
|
|
|
|
Not a literal, 0x0 (but it should be, it should point to swap)
|
|
|
|
push 0x23 sub R[0] <- R[0] 0x4 immediate
|
|
0x24 sub R[5] <- R[5] 0x0 immediate
|
|
0x25 BR EQ 0x6 immediate
|
|
> 0x26 sub R[2] <- R[5] R[0]
|
|
0x27 BR HI 0x1 immediate
|
|
0x28 and R[2] <- R[2] 0x7fff immediate
|
|
0x29 lsl R[2] <- R[2] 0xf immediate
|
|
0x2a ior R[2] <- R[2] 0x4 immediate
|
|
0x2b BR T 0x1 immediate
|
|
|
|
line 68
|
|
|
|
0xfe4 r0 SP
|
|
0x28c r2 TOS
|
|
0x1270 r5 TermAddr
|
|
|
|
push 0x23 sub R[0] <- R[0] 0x4 immediate
|
|
0x24 sub R[5] <- R[5] 0x0 immediate
|
|
0x25 BR EQ 0x6 immediate
|
|
0x26 sub R[2] <- R[5] R[0]
|
|
0x27 BR HI 0x1 immediate
|
|
0x28 and R[2] <- R[2] 0x7fff immediate
|
|
> 0x29 lsl R[2] <- R[2] 0xf immediate
|
|
0x2a ior R[2] <- R[2] 0x4 immediate
|
|
0x2b BR T 0x1 immediate
|
|
jpel 0x2c mov R[2] <- 0x4
|
|
done 0x2d store R[2] -> ram[R[0]]
|
|
0x2e BR T -0x21 immediate
|
|
|
|
line 75
|
|
|
|
|
|
|
|
|
|
==================================================
|
|
|
|
iball * 2
|
|
|
|
0xfeac0000 r2
|
|
|
|
|
|
0xc0 r7
|
|
|
|
0x67 load R[3] <- ram[R[6]]
|
|
iball 0x68 lsl R[7] <- R[3] 0x2 immediate
|
|
0x69 asr R[7] <- R[7] 0x11 immediate
|
|
0x6a BR EQ 0x1 immediate
|
|
> 0x6b add R[7] <- R[7] R[6]
|
|
0x6c lsl R[8] <- R[3] 0x11 immediate
|
|
0x6d asr R[8] <- R[8] 0x11 immediate
|
|
0x6e BR EQ 0x1 immediate
|
|
0x6f add R[8] <- R[8] R[6]
|
|
0x70 mov R[6] <- R[8]
|
|
|
|
0x0 r8
|
|
|
|
0x70 mov R[6] <- R[8]
|
|
> 0x71 sub R[0] <- R[0] 0x4 immediate
|
|
0x72 sub R[8] <- R[8] 0x0 immediate
|
|
0x73 BR EQ 0x8 immediate
|
|
0x74 sub R[7] <- R[7] 0x0 immediate
|
|
0x75 BR EQ 0x2 immediate
|
|
0x76 sub R[7] <- R[7] R[0]
|
|
0x77 and R[7] <- R[7] 0x7fff immediate
|
|
0x78 lsl R[7] <- R[7] 0xf immediate
|
|
0x79 ior R[7] <- R[7] R[9]
|
|
0x7a store R[7] -> ram[R[0]]
|
|
0x7b BR T 0xb immediate
|
|
> 0x7c sub R[7] <- R[7] 0x0 immediate
|
|
0x7d BR EQ 0x2 immediate
|
|
0x7e sub R[7] <- R[7] R[0]
|
|
0x7f and R[7] <- R[7] 0x7fff immediate
|
|
0x80 sub R[1] <- R[1] 0x0 immediate
|
|
0x81 BR EQ 0x2 immediate
|
|
|
|
|
|
|
|
===================================================
|
|
|
|
Looksgood so far...
|
|
|
|
but we just loaded
|
|
> 0x67 load R[3] <- ram[R[6]]
|
|
|
|
and the value in r3 is malformed:
|
|
|
|
In [14]: x = 0xfeac0000
|
|
|
|
In [15]: bin(x)
|
|
Out[15]: '0b11111110101011000000000000000000'
|
|
|
|
In [16]: len(_)-2
|
|
Out[16]: 32
|
|
|
|
We just loaded that at line 123
|
|
load(TERM, TEMP0),
|
|
|
|
Ah!
|
|
|
|
I think it's that expr_cell/2 doesn't zero out the top two bits for
|
|
records that have negative head offsets.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PC == 0
|
|
PC == 0x25
|
|
|
|
ram[R[0]]
|
|
ram[R[1]] |