Thun/thun/markII.rst

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]]